参考
- 作者开发的QQ机器人 - 可以通过这个机器人看P站图
- QQ群 - Javascript高级爬虫 - 作者自建群,欢迎加入!
- 国内可用的P站API - 口味不叼的童鞋可以直接食用,避免麻烦
概述
看P站其实只是个冷门需求,不过本篇文章主要是为了提供一个解决方案:让原本无法在围城内使用的库通过添加socks5代理支持而变成可用。
本地验证
在之前的文章里介绍了一个国内可以直接使用的P站API,但是发现有些排行模式没有数据,比如“受男性欢迎”(mode=male),导致搜出来的图不是我想要的那些,于是开始在Github上找其它方案。
很容易就找到了一个pixiv-app-api,是浏览器端和node.js都可以使用的,基于Pixiv官方APP的API。
当然了,由于众所周知的原因,Pixiv是没办法从国内直接访问到的。不过这难不住码农,只要用某乳就可以了。在完全不修改模块内部代码的情况下,只要在调用pixiv-app-api之前,用下面的代码设置一下全局代理即可:
process.env.http_proxy = 'http://127.0.0.1:1080'
process.env.https_proxy = 'http://127.0.0.1:1080'
然后本地验证了一下,嗯,可以正常登录和查询!
那么,下一步就是如何在服务器上也搞起了。
服务器安装某乳客户端
其实某乳的python版中就自带客户端的,没错,就是那个local.py(在子目录里)!
不过注意,要克隆某乳的manyuser分支,master分支不支持部分参数,比如混淆参数。
下面这段shell命令行就可以后台启动客户端了:
python local.py -b 127.0.0.1 -l 1080 -s <某乳服务器IP> -p <服务器端口> -k <密码> -m <加密> -O <协议> -o <混淆> -d start
其中:
-
某乳服务器IP
,服务器端口
,密码
,加密
,协议
,混淆
这几个和Windows版客户端的几个参数一一对应即可。 -
-b 127.0.0.1
表示本地代理服务只允许服务器本地应用使用。如果你不想你的服务器被人家扫出来然后反复蹂躏,就不要设成0.0.0.0。 -
-l 1080
是本地代理的端口号,socks5代理习惯上用1080端口,当然你可以改成别的。
不过我是用pm2启动的,这样以后重启就不需要记这么长的命令行了:
pm2 start "local.py -b 127.0.0.1 -l 1080 -s <某乳服务器IP> -p <服务器端口> -k <密码> -m <加密> -O <协议> -o <混淆> start" --name mySocks5Proxy
启动以后可以在服务器上用curl来验证一下:
curl -x socks5h://localhost:1080 https://www.google.com
上面就是curl中使用socks5代理的方法,socks5h表示由某乳服务器(而不是客户端)负责解析域名。
在node.js中使用socks5代理
如前一步所示,python版某乳客户端只有socks5代理,而没有http代理。也就是说在“本地验证”一节中采用的改环境变量的简单方案是没法直接使用的,有两条路可以走:
- 使用privoxy把socks5代理转成http代理,其实最常用的C#版Windows客户端就是这个方案
- 魔改pixiv-app-api的代码,直接用socks5代理!
因为我不想引入新的外部依赖,因此选择第二条路,直接改代码。
分析了一下pixiv-app-api的源码,它是使用axios作为http请求库,axios是支持socks5代理的,只要安装socks-proxy-agent这个npm模块即可,示例代码如下:
const SocksProxyAgent = require('socks-proxy-agent')
const httpsAgent = new SocksProxyAgent('socks://127.0.0.1:1080')
axios.get('https://www.google.com', { httpsAgent }).then(console.log)
魔改pixiv-app-api,添加socks5代理支持
这一步就比较简单了:
-
首先确保你已经安装了pixiv-app-api和socks-proxy-agent模块
cnpm install pixiv-app-api socks-proxy-agent
- 找到node_modules/pixiv-app-api/dist/index.js
-
第一处:加三行代码
const baseURL = 'https://app-api.pixiv.net/'; const SocksProxyAgent = require('socks-proxy-agent'); // << 添加一行 const httpsAgent = new SocksProxyAgent('socks://127.0.0.1:1080'); // << 添加一行 const instance = axios_1.default.create({ baseURL, headers: { 'App-OS': 'ios', 'App-OS-Version': '9.3.3', 'App-Version': '6.0.9', }, httpsAgent // << 添加一行 });
-
第二处:小小修改,加个参数
const axiosResponse = await axios_1.default.post('https://oauth.secure.pixiv.net/auth/token', querystring_1.stringify(decamelize_keys_1.default(data)), { headers, httpsAgent }); // << 此行加一个httpsAgent参数
经过以上修改,pixiv-app-api终于可以在服务器上正常使用了,以下是示例代码,注意调用api只是用来查询插画排行榜数据,图片实际上是从墙内可用的CDN即i.pixiv.cat上下载的。
const path = require('path')
const rp = require('request-promise')
const fs = require('fs-extra')
const PixivAppApi = require('pixiv-app-api')
;(async () => {
const pixiv = new PixivAppApi('pixiv网站账户', 'pixiv网站密码', { camelcaseKeys: true })
let res = await pixiv.login()
console.log('login: ', res)
res = await pixiv.illustRanking({ mode: 'week_r18' })
const ids = res.illusts.map(o => o.id + '')
const urls = res.illusts.map(o => o.imageUrls.medium).map(u => u.replace('i.pximg.net', 'i.pixiv.cat'))
res = await Promise.all(urls.map(u => rp.get(u, { encoding: null })))
await Promise.all(res.map((buf, i) => {
const fn = path.join(__dirname, 'pixiv_tmp', ids[i] + '.jpg')
return fs.writeFile(fn, buf)
}))
})()