因为要收集数据,所以打算自己撸一个爬虫,期间碰到网站的反爬措施,让我非常头疼,在此记录一下。

基础

爬虫的基础是不需要自己手动通过浏览器访问网页,而是通过程序构造网络请求,获取网站返回的结果。例如使用python的requests库发送请求:

import requestsurl = 'https://www.baidu.com'
ret = requests.get(url)
print(ret.text)

得到返回的html代码后,可以自己解析数据,获取感兴趣的内容。

前期分析

首先分析要爬的网站,本质是一个信息查询系统,提供了搜索页面。例如我想获取某个case,需要利用这个case的id或者name字段,才能搜索到这个case的页面。因为我是希望数据尽可能不同,id和name分布得比较广泛,自己构造的话特别麻烦,于是看看有没有什么别的办法。

好在网站还提供了热搜功能,可以点击热搜链接,获取每日/周/月的热搜条目,每个热搜榜单有50条信息。热搜的网站链接是www.xxx.com/search?city=0 ,并且网站还提供了各地查询系统的链接,例如tj.xxx.com/search?city=2 ,tj是天津的缩写,2应该就是城市对应的索引。

前期的信息就那么多,先构造个请求试试:

可以看到服务器网站返回的状态码是521,后面是返回的text,看起来是个js脚本。

没有正常的返回状态,我首先想到的是用浏览器打开时,本地会保存cookies,可能是cookies没对上。后来经过验证,确实如此。

绕过反爬虫

出于对安全的考虑,有些网站会做一些反爬的措施,例如前面说的需要判断user-angent和cookies,或者判断请求的ip是否在短时间内多次访问。该网站用的是知道创宇的安全服务,频繁访问会提示ip行为不正常。

爬到的结果

浏览器本质也是一个应用程序,只要ip不被封,既然可以通过浏览器访问,那么我们自己写程序来请求也是应该没有问题的。

一些常见的绕过反爬虫的措施有:

  • 构造消息头:如上所说的user-angent和cookies都包含在消息头当中。
  • 延长请求间隔:如果快速频繁的发送请求,会大量抢占服务器资源,一般这种情况下很容易被网站的安全措施检测出来并且封掉ip。所以适当的延长请求间隔,例如随机隔2-5秒不等再发送下一次请求。
  • 使用代理ip,解决ip检测问题。

这些使用和实现起来都不是很麻烦,网上资料也比较多。

实战

前面说到该网站需要cookies才能正常返回,但是该网站的cookies过期很快,我总不能用浏览器开发者工具获取cookies,然后让程序跑一会儿,每隔几分钟再手动获取cookies,再让程序继续跑吧。如果反复这样工作,那么写爬虫也就没意义了。便开始对cookies进行分析。

从浏览器的开发者工具获取到的cookies大约有10个字段,经过反复测试,能让网站正常返回的只需要两个字段,分别为__jsluid_h=011a522dbxxxxxxxxc1ce59d336e5e60__jsl_clearance=1581880640.794|0|trTB4c6b%2BZpvxxxxxxxx8YqCOOo%3D (中间打码处理)。

经过测试,如果请求的时候不自己构造cookies,默认会返回__jsluid_h

我似乎明白了什么,看到之前返回那堆看不懂的js脚本,奥妙一定就在其中!

先尝试了将那段js脚本保存下来,包装成一个html文件打开,发现浏览器不停的刷新,也并没起什么作用。那就分析一下js脚本,原来的代码是单行的,自己整理一下并加了一些变量名和log,大概是这么个样子:

第一次脚本

将第16行的变量cmd打印出来看看,发现是另一段类似的脚本:

第二次脚本

可以看到第二段脚本已经开始设置cookies的__jsl_clearence 字段了。这些显然就是混淆后的js脚本,但是分析到这里也就大概弄明白了从发送请求到网站返回是怎么回事。之所以在本地跑这段代码会不断刷新,是因为第二行的setTimeout会让其在1.5秒后重新请求,但是我们本地没有服务处理请求让其停止,所以会不断的刷新。

而第一段脚本当中,变量y是完整的js代码 ,代码中的变量名和关键字被进行编码了,变量x存储的是用来替换的变量名和关键字,后面是解码函数。所以现在的问题变成了获取第一段脚本当中的cmd代码,执行后再获取第二段代码的document.cookie的内容即可。

可是对于python和js的交互我完全没接触过,尝试了PyExecJS和Js2Py,都没办法正常执行第一段脚本。无奈之下,我用python复现了第一段脚本,然后用Js2Py获取了cookie。在请求一次过后,构造cookies,再请求一次,就可以了:

def test():url = REQUEST_URL# url = 'https://www.baidu.com'request_header = get_header()html = requests.get(url, headers=request_header)print(html)jscode = html.text# print(jscode)# tryjs.get_cookies()为复现的js代码,以及用Js2Py获取cookies的代码request_cookies = try_js.get_cookies(jscode) request_cookies += ';__jsluid_h=' + html.cookies['__jsluid_h']request_header['Cookie'] = request_cookiesprint(request_header)html = requests.get(url, headers=request_header, timeout=5)print('new connection')print(html)print(html.text)

其它

在实际操作中,我使用了西刺代理提供的代理ip,全军覆没。可能是网站的安全系统默认屏蔽了这些ip,所以最终我还是用自己的本机ip发送请求。

根据我的网络与服务器的实际情况,我将请求间隔设置为10-20秒,超时设置为15秒。

因为我并不要求爬取网站的所有数据,所以有些返回不正常的页面和条目可以忽略,在处理和清晰的时候去掉这些数据即可。

经过麓战20多小时,差点就吐了,还好最终爬虫成功跑了起来。

python 获取html js 变量_Python爬虫与反反爬虫实践相关推荐

  1. Python零基础速成班-第12讲-Python获取网络数据Socket,API接口,网络爬虫Crawler(制作弹幕词云)

    Python零基础速成班-第12讲-Python获取网络数据Socket,API接口,网络爬虫Crawler(制作弹幕词云) 学习目标 获取网络数据Socket API接口 网络爬虫Crawler(制 ...

  2. python获取当前路径的方法_Python获取脚本所在目录的正确方法【转】

    原博文 2015-09-24 10:21 − 1.以前的方法如果是要获得程序运行的当前目录所在位置,那么可以使用os模块的os.getcwd()函数.如果是要获得当前执行的脚本的所在目录位置,那么需要 ...

  3. python获取a股数据_python获取A股数据列表的例子

    2015年的股市是当下的热门话题,同事的朋友弄了一个简单的弹股吐槽单页面单日PV就能达30W+ ,相当于本博客一年的PV量.所以站在技术角度,这里也写几篇关于股票技术面的文章.首先本篇先从获取A股列表 ...

  4. python获取局域网在线主机_python通过scapy获取局域网所有主机mac地址示例

    python通过scapy获取局域网所有主机mac地址示例 发布于 2014-10-10 20:34:48 | 607 次阅读 | 评论: 0 | 来源: 网友投递 Python编程语言Python ...

  5. python获取url返回值_python获取url的返回信息方法

    如下所示: #!/usr/bin/env python # -*- coding: utf-8 -*- import os import sys import urllib import urllib ...

  6. python获取系统时间月份_python 取数组绝对值python获取当前日期

    今天群里一个人问了怎么获取当前时间的问题,以前接触过计算日期之差的,具体代码如下: import datetime d1=datetime.datetime(2014,3,14) d2=datetim ...

  7. python获取文件的大小_python获取文件大小

    python获取文件大小# !/usr/bin/python3.4 # -*- coding: utf-8 -*- import os # 字节bytes转化kb\m\g def formatSize ...

  8. python获取系统时间函数_Python常用时间操作总结【取得当前时间、时间函数、应用等】...

    本文实例讲述了Python常用时间操作.分享给大家供大家参考,具体如下: 我们先导入必须用到的一个module >>> import time 设置一个时间的格式,下面会用到 > ...

  9. python获取某文件路径_Python获取当前文件路径

    一. Python 获取当前文件路径方法 2. sys.path[0] 获取文件当前工作目录路径(绝对路径) sys.argv[0]|获得模块所在的路径(由系统决定是否是全名) 若显示调用python ...

最新文章

  1. 如何团队协作,代码托管?Git使用教程:最详细、最浅显、一文读懂Git常用操作!...
  2. 5.springMVC数据回显(就是后台向页面传参的过程)
  3. TS流解析之PMT表格解析
  4. 设置sqlplus环境变量
  5. adb logcat 抓取日志_App专项测试操作指南-2- 常见的ADB命令(上)
  6. android wi-fi_如何在Android手机上查找3G或Wi-Fi速度
  7. 漫画:如何用Zookeeper实现分布式锁?
  8. 【生活资讯】5款好用的生活学习类APP
  9. nginx(三)反向代理和负载均衡
  10. python元祖切片_Python
  11. 下载了linux版redis怎么用,Linux下redis的安装与使用图文教程
  12. Oracle oci.dll 下载地址
  13. 微信小程序Scope参数错误或没有Scope权限的处理方法
  14. 奖券数目 有些人很迷信数字,比如带“4”的数字,认为和“死”谐音,就觉得不吉利。 虽然这些说法纯属无稽之谈,但有时还要迎合大众的需求。某抽奖活动的奖券号码是5位数(10000-99999),要求其
  15. MySQL常规篇之增删改查(精选)
  16. java zip文件加密_java自动压缩文件并加密
  17. 第一阶段冲刺 eighth day
  18. Android学习笔记之activity间传递传递参数
  19. 青村茶舍||“清明寄哀思”乡风建设活动
  20. mstsc.js远程桌面NODE_RDP_PROTOCOL_X224_NEG_FAILURE错误

热门文章

  1. 06-CA/TA编程:rsa demo
  2. [architecture]-ARMV7架构下SecureMonitor双系统切换时保存和恢复哪些寄存
  3. 三方登录(微博为例)
  4. Java Socket 客户端使用指定端口多次连接服务器引发 BindException
  5. ReverseMe-120(base64解码表) 逆向寒假生涯(21/100)
  6. 11、Java Swing JList:列表框组件
  7. 限制Textarea文本域内容的长度
  8. 寒假每日一题(提高组)【Week 3 完结】
  9. 2021春季每日一题【week8 未完结】
  10. 【C / C++】关于数组默认初值问题