一个免费ss网站的数据爬取过程

Apr 14, 2019

引言

偶然发现一个免费ss分享网站,本以为简单的url请求即可获取数据。但是没想到在网站的反爬机制很严格,这反而激起了我的好奇心。

不过对于爬虫经验技术来说,是一个很好的学习检验的机会。

爬虫整体概况

数据获取的核心是围绕2个http请求

方法 地址 参数 备注
get url 响应源码中有可用信息
post url1 a,b,c 返回加密数据文本

主要功能方法

绕过DDOS保护(Cloudflare)

简单来讲cloudflare就是通过js验证访问是否来至真正的web浏览器。

如上图所示,访问url 时候一般会进入5秒左右倒计时;请求状态码是503。
通过抓包可以看到503请求数秒后跳转一个类似“https://xxxxx/cdn-cgi/l/chk_jschl?s=xxx”的302请求,成功后即可跳转到期望页面。

解决方法:使用任意一个第三方库:cloudflare-scrape 或者 cloudflare-scrape-js2py
这2个库方法通用,安装cloudflare-scrape-js2py方法如下:

12
$ git clone https://github.com/VeNoMouS/cloudflare-scrape-js2py.git$ sudo python3 setup.py install

由于Cloudflare不断改变和强化其保护页面,最初使用的 cloudflare-scrape很快就不能用了,当然可以去提交问题或者查看相关问题的解决方案。
我也是各种尝试各种查,不过最后换了 cloudflare-scrape-js2py就解决了问题。

主要代码如下:

123456
session = requests.session()scraper = cfscrape.create_scraper(sess=session)scraper = cfscrape.create_scraper(delay=11)

req = scraper.get(url)html = req.text

post中参数a,b,c的解析

get->url 返回源码如下图(部分):

post中参数a,b,c的解析

网页源码js中的参数a,b,c
解析a,b,c参数主要是依赖正常显示的url的源码中的js代码,如下图重点地方以划出。
上图第一个被划线的一句js如下:

123456789
if (detect) {    var a = '317d2cefb40586a9';    var b = 'e1a5f5499211cbd4';    var c = 'e59ab31720d6cf48';} else {    var b = 'e59ab31720d6cf48';    var c = '317d2cefb40586a9';    var a = 'e1a5f5499211cbd4';}

根据多次观察,可知每次需要取else中的a,b,c的值,代码如下:

12345678
# 获取页面源码中else{后面的abc的值# 参数值只能为: 'a' ,'b', 'c'def get_var_abc(key='a'):    # 反向查找 并截取    ivs = key + "='"    ivl = html.rindex(ivs)    key = html[ivl + len(ivs): ivl + len(ivs) + 16]    return key

二维码(base64文本)解码
上图中docodeImage方法中第一个参数值如下:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAABXAQMAAABLBksvAAAABlBMVEX///8AAABVwtN+AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAq0lEQVQ4jc3Ruw0DIQwGYEcu3B0LRGINOmbKAgm3AKxExxpIXiDXUURxjkgnXXExKe+vPjfgB8DZYkQisEhVPAEGwgCqPUePqQ2cMo8tOPAf/fT+3W6WI6+5bPhlIxjd1bSqePIv0+TtNAPhUjCJ5vW1R5ZIukUaLw0U97LYuWhe9xDIBtLc9+nq3VXNnufMEQaODm7ffzUTL1k1YCr83G596H5fstJA8bnyAVNpDVwJjnB4AAAAAElFTkSuQmCC

这个参数值相当于一个图片的base64编码,其实就是一个二维码。
这个二维码是一个长度为16的字符,其实也是post中的一个参数值。

代码如下:

1234567
# 直接通过base64字符串解析二维码;获取二维码的值def decode_qrcode(html):    qrdatas = html.split('data:image/png;base64,')[1].split("',")[0]    qrbytes = bytes(qrdatas, encoding="ascii")    decode_result = decode(Image.open(BytesIO(codecs.decode(qrbytes,'base64'))))    qrvalue =str(decode_result[0].data, encoding='utf-8')    return qrvalue

post参数a,b,c值的确定

上图中的一段省略版的js代码如下:

123
decodeImage('data:image/png;base64,iVBORw0KGxx...xxwJjnB4AAAAAElFTkSuQmCC',     function(c) {        $.post("data.php",{a:a,b:b,c:encc(c)},

多次观察发现function(key)方法中的参数随机a,b,c任一,而这个随机参数(a/b/c)需要用二维码的值来替代。
说明:post中的a,b,c的值是依赖js中的a,b,c的值和二维码的值,所以a,b,c的值要注意以免混淆。

代码如下:

1234567891011121314151617181920
# 根据规则分别求出3种情况下的a,b,cdef get_param_abc(html):    a = get_var_abc(key='a')    b = get_var_abc(key='b')    c = get_var_abc(key='c')    symbolKey = html.split('data:image/png;base64,')[1].split("function(")[1][:1]    print('symbolKey',symbolKey)    print(symbolKey=='a',symbolKey=='b',symbolKey=='c')    if symbolKey == 'a':        a = decode_qrcode(html)    elif symbolKey == 'b':        b = decode_qrcode(html)    elif symbolKey == 'c':        c = decode_qrcode(html)

    # js2py.translate_file('encc.min.js', 'encc.py')    from encc import PyJsHoisted_encc_    c = PyJsHoisted_encc_(c).value    print('\n%s\n%s\n%s'% (a,b,c))    return a,b,c

post参数c的值的加密

12345
$.post("data.php", {    a: a,    b: b,    c: encc(c)},

这一行是js中post的请求,是固定的对参数c进行加密,网站中的js加密算法比较清晰。
这时的思路有3种:

  1. 直接通过python执行js代码;
  2. 第三方(库)自动代码转换( js->python );
  3. 根据js中的加密思想,手动进行python编码;

比较推荐前2种方法,毕竟第3种手动转码太难太耗时间。
这里推荐2个执行js的库:Js2Py,PyExeJs
本文使用的是Js2Py,这个强大的库可以直接执行js代码和转换js文件。

所以这行js对应的python代码为:

1234567
a,b,c = get_param_abc(html)

#post提交a,b,c,得到密文payload = {'a':a,'b':b,'c':c}session.cookies = scraper.cookies  # 必须带上cookiesreq = scraper.post(url2,data=payload)msg = req.text

AES加密数据解码

确定AES加密模式(弃用)

最初是想用判断语句指定加密模式参数,但有幸后来看到大牛的好方法。
不过有一个小点需要说明一下,就是可以从js源码中分析出来加密参数;
如上节图上被括起来的js文本如下:

1234567891011
//js eval加密文本eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('1 2=\'4\'+\'h\'+\'8\'+\'9\'+\'a\';1 5=\'3\'+\'6\';1 7=0.b.g(d,i,{c:e,2:0.2.4,f:0.5.3});',19,19,'CryptoJS|var|mode|Pkcs7|CBC|pad|ZeroPadding|dec|CTR|ECB|OFB|AES|iv||y|padding|decrypt|CFB|x'.split('|'),0,{}))

//js 解密(解压缩)后的文本var mode = 'CBC' + 'CFB' + 'CTR' + 'ECB' + 'OFB';var pad = 'Pkcs7' + 'ZeroPadding';var dec = CryptoJS.AES.decrypt(d, x, {    iv: y,    mode: CryptoJS.mode.CBC,    padding: CryptoJS.pad.Pkcs7});

免判断加密模式并解密(推荐)

中间和朋友电话闲聊中问过一句模式的选择,朋友只是说模式不重要;当时就觉得应该有一种遍历类型的解法。

根据js代码可知:下面python代码的decrypt_data方法的参数key,iv分别对应post参数的a,b;即:

12345
endata = base64.b64decode(msg)key = bytes(a,encoding="utf-8")iv  = bytes(b,encoding="utf-8")

ssdata = decrypt_data(key, iv, endata)

由此对应的python代码如下:

123456789101112131415161718192021
"""解密数据得到ss信息,返回list对象"""def decrypt_data(key, iv, endata):    ctr = Counter.new(128, initial_value=int(binascii.hexlify(iv), 16))    modes = [        AES.new(key, AES.MODE_ECB),        AES.new(key, AES.MODE_CBC, iv),        AES.new(key, AES.MODE_OFB, iv),        AES.new(key, AES.MODE_CTR, counter=ctr),        AES.new(key, AES.MODE_CFB, iv, segment_size=128)    ]    rtdatas = None    for mode in modes:        try:            dec = mode.decrypt(endata).decode('utf-8')            print(dec[-200:])     # 解密后文本结尾可能存在'\0'            dec = dec.rstrip('\0')  # 去除结尾空白符'\0'            rtdatas = json.loads(dec)['data']            break        except:            pass    return rtdatas

网站的加密模式是5种的随机的一种,其中可能遇到CFB模式中会报错,后来发现pycryto的版本问题,安装pycrytodome即可。

解码数据并测延时

post密文解密后是json的文本,下图是格式化片段:

账号的处理及测试可参考github大神的方法:检测程序介绍

最后

对于这个网站学习挺好,其他就不要多想了。

相关资源

本文相关库

python=3.6.5
brotli=1.0.7
cfscrape=2.0.3
requests=2.21.0
Js2Py=0.60
Pillow=5.1.0 # Pillow(PIL Fork)
cryptodemo=0.0.1

第三方开源库

https://github.com/Anorov/cloudflare-scrape
https://github.com/VeNoMouS/cloudflare-scrape-js2py

https://github.com/PiotrDabkowski/Js2Py

在线测试工具

在线二维码-Convert Your Base64 to Image
https://codebeautify.org/base64-to-image-converter
js在线解密/美化
https://tool.lu/js/
在线json解析
https://www.sojson.com/


参考

binascii.Error: Incorrect padding, even when string length is multiple of 4
https://stackoverflow.com/questions/45879045/binascii-error-incorrect-padding-even-when-string-length-is-multiple-of-4

python字符串str和字节数组相互转化
https://www.cnblogs.com/hhh5460/p/5243305.html

Python3操作二维码图片
http://blog.niuhemoon.xyz/pages/2018/04/27/Python3-QRcode/

关于xxx网站js加密算法的研究
https://github.com/gcdd1993/analyzeSS

Python爬取某站ke xue上网帐号(5.15更新)

https://mtaoist.xyz/2018/04/07/python-getss/
xiaoTaoist:Auto-Shadowsocks项目
https://github.com/xiaoTaoist/Auto-Shadowsocks

一个免费ss网站的数据爬取过程的更多相关文章

  1. 记一次wiki数据爬取过程

    最近有个爬取各国领导人信息的奇怪需求,要求百度和维基两种版本的数据,最要命的还要保持数据的结构不变.正好印象中隐约记得维基有专门的领导人列表页,不考虑爬取下来的格式不变的话应该很好爬的样子. 首先思路 ...

  2. 芝麻HTTP:JavaScript加密逻辑分析与Python模拟执行实现数据爬取

    本节来说明一下 JavaScript 加密逻辑分析并利用 Python 模拟执行 JavaScript 实现数据爬取的过程.在这里以中国空气质量在线监测分析平台为例来进行分析,主要分析其加密逻辑及破解 ...

  3. 中国农产品信息网站scrapy-redis分布式爬取数据

    ---恢复内容开始--- 基于scrapy_redis和mongodb的分布式爬虫 项目需求: 1:自动抓取每一个农产品的详细数据 2:对抓取的数据进行存储 第一步: 创建scrapy项目 创建爬虫文 ...

  4. requests模块处理cookie,代理ip,基于线程池数据爬取

    引入 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时,如果使用之前requests模块常规操作时,往往达不到我们想要的目的. 一.基于requests模块 ...

  5. Python爬虫入门教程 15-100 石家庄政民互动数据爬取

    石家庄政民互动数据爬取-写在前面 今天,咱抓取一个网站,这个网站呢,涉及的内容就是 网友留言和回复,特别简单,但是网站是gov的.网址为 http://www.sjz.gov.cn/col/14900 ...

  6. Python爬虫入门教程 3-100 美空网数据爬取

    美空网数据----简介 从今天开始,我们尝试用2篇博客的内容量,搞定一个网站叫做"美空网"网址为:http://www.moko.cc/, 这个网站我分析了一下,我们要爬取的图片在 ...

  7. 人人贷网的数据爬取(利用python包selenium)

    记得之前应同学之情,帮忙爬取人人贷网的借贷人信息,综合网上各种相关资料,改善一下别人代码,并能实现数据代码爬取,具体请看我之前的博客:http://www.cnblogs.com/Yiutto/p/5 ...

  8. Web Scraper——轻量数据爬取利器

    日常学习工作中,我们多多少少都会遇到一些数据爬取的需求,比如说写论文时要收集相关课题下的论文列表,运营活动时收集用户评价,竞品分析时收集友商数据. 当我们着手准备收集数据时,面对低效的复制黏贴工作,一 ...

  9. 爬虫05 /js加密/js逆向、常用抓包工具、移动端数据爬取

    爬虫05 /js加密/js逆向.常用抓包工具.移动端数据爬取 目录 爬虫05 /js加密/js逆向.常用抓包工具.移动端数据爬取 1. js加密.js逆向:案例1 2. js加密.js逆向:案例2 3 ...

随机推荐

  1. LeetCode——First Bad Version

    Description: You are a product manager and currently leading a team to develop a new product. Unfort ...

  2. 【黑金ZYNQ7000系列原创视频教程】01.熟悉vivado——纯逻辑led实验

    黑金论坛地址: http://www.heijin.org/forum.php?mod=viewthread&tid=36627&extra=page%3D1 爱奇艺地址: http: ...

  3. salt-ssh的批量脚本及使用方法

    author: headsen   chen date : 2018-08-02   20:06:06 1,salt-ssh的安装: yum -y install epel-release yum - ...

  4. 代码片段,Lucene的高亮显示

    代码高亮显示是通过在搜索到的Term中把匹配了用户输入的关键字的周围加上一些标记来实现(比如,关键字是 "中华" 查到的一个Term是 "中华人民共和国",则把 ...

  5. mac必装工具以及mac使用介绍

    必装工具 Scroll Reverserhttp://pilotmoon.com/scrollreverser/:一款可以使得鼠标使用方式和windows系统一致的软件 编程工具 ,,,,, 常用快捷 ...

  6. MUI窗口管理

    参考:窗口管理 http://dev.dcloud.net.cn/mui/window/ 页面初始化:在app开发中,若要使用HTML5+扩展api,必须等plusready事件发生后才能正常使用,m ...

  7. Common Subsequence 最大公共子序列问题

    Problem Description A subsequence of a given sequence is the given sequence with some elements (poss ...

  8. 扫描类APP推荐

    扫描全能王 (com.intsig.camscanner) - 5.10.0.20190426 - 应用 - 酷安网 应该是手机上最好的扫描类 APP 了,没有之一.只是因为付费太贵. 感谢酷安评论区 ...

  9. Windows安装使用git

    下载安装Windows安装文档Git-2.16.2-64-bit双击安装(安装过程不详述) 打开git客户端 新建代码命令 mkdir /c/code 进入该目录(对应windows的c盘下面的目录) ...

  10. 终于修好了MacBook

    之前由于Trackpad故障,陆家嘴苹果店开了维修单,让我在2周内去更换,详见第二次去苹果店维修MacBook. 后来由于购买了AppleCare进行延保,又担心放在那维修时间长,就懒得去更换了. 昨 ...