神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

1 前言

近期,有些朋友问我一些关于如何应对反爬虫的问题。因为好多朋友都在问,所以决定写一篇此类的博客。把我知道的一些方法,分享给你们。博主属于小菜级别,玩爬虫也彻底是处于兴趣爱好,若有不足之处,还望指正。html

在互联网上进行自动数据采集(抓取)这件事和互联网存在的时间差很少同样长。今天大众好像更倾向于用“网络数据采集”,有时会把网络数据采集程序称为网络机器人(bots)。最经常使用的方法是写一个自动化程序向网络服务器请求数据(一般是用 HTML 表单或其余网页文件),而后对数据进行解析,提取须要的信息。python

说句实在话,若是个人网站老是让人爬来爬取的,常常被虚拟访问者骚扰,我也是蛮烦的,并且若是遇到“霸道”一点的爬虫,都能直接把服务器卡死。所以,咱们在爬取别人网站的时候,也多为对方考虑考虑。不过话说回来,我却没有这个烦恼,为何呢?由于我根本就没有本身的网站。=.=linux

2 黑科技

网站防采集的前提就是要正确地区分人类访问用户和网络机器人。如今网站有不少技术来防止爬虫,好比验证码,对于一些简单的数字验证码,可使用训练好的caffemodel诸如此类的模型去识别,准确率仍是能够的。固然,也能够在Github搜一搜关于验证码识别的东西,看一看大牛们是怎么玩的。除了这些高大上的,还有一些十分简单的方法可让你的网络机器人看起来更像人类访问用户。程序员

2.1 构造合理的HTTP请求头

除了处理网站表单,requests 模块仍是一个设置请求头的利器。HTTP 的请求头是在你每次向网络服务器发送请求时,传递的一组属性和配置信息。HTTP 定义了十几种古怪的请求头类型,不过大多数都不经常使用。web

每一个网站都有不一样的请求头,如何获取这个请求头呢?能够用我从前提到过的Fiddler或者审查元素的方法,咱们能够根据实际状况进行配置。例如,GET百度根目录的时候,须要添加的请求头信息以下:正则表达式

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?    部分参数说明:shell

  • Upgrade-Insecure-Requests:参数为1。该指令用于让浏览器自动升级请求从http到https,用于大量包含http资源的http网页直接升级到https而不会报错。简洁的来说,就至关于在http和https之间起的一个过渡做用。就是浏览器告诉服务器,本身支持这种操做,我能读懂你服务器发过来的上面这条信息,而且在之后发请求的时候不用http而用https;
  • User-Agent:有一些网站不喜欢被爬虫程序访问,因此会检测链接对象,若是是爬虫程序,也就是非人点击访问,它就会不让你继续访问,因此为了要让程序能够正常运行,咱们须要设置一个浏览器的User-Agent;
  • Accept:浏览器可接受的MIME类型,能够根据实际状况进行设置;
  • Accept-Encoding:浏览器可以进行解码的数据编码方式,好比gzip。Servlet可以向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这能够减小5到10倍的下载时间;
  • Accept-Language:浏览器所但愿的语言种类,当服务器可以提供一种以上的语言版本时要用到;
  • Cookie:这是最重要的请求头信息之一。中文名称为“小型文本文件”或“小甜饼“,指某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(一般通过加密)。定义于RFC2109。是网景公司的前雇员卢·蒙特利在1993年3月的发明。

2.2 设置Cookie的学问

虽然 cookie 是一把双刃剑,但正确地处理 cookie 能够避免许多采集问题。网站会用 cookie 跟踪你的访问过程,若是发现了爬虫异常行为就会中断你的访问,好比特别快速地填写表单,或者浏览大量页面。虽然这些行为能够经过关闭并从新链接或者改变 IP 地址来假装,可是若是 cookie 暴露了你的身份,再多努力也是白费。数据库

在采集一些网站时 cookie 是不可或缺的。要在一个网站上持续保持登陆状态,须要在多个页面中保存一个 cookie。有些网站不要求在每次登陆时都得到一个新 cookie,只要保存一个旧的“已登陆”的 cookie 就能够访问。windows

若是你在采集一个或者几个目标网站,建议你检查这些网站生成的 cookie,而后想一想哪个 cookie 是爬虫须要处理的。有一些浏览器插件能够为你显示访问网站和离开网站时 cookie 是如何设置的。例如:EditThisCookie,该插件能够谷歌商店进行下载。URL:http://www.editthiscookie.com/api

Cookie信息,也能够更具实际状况填写。不过requests已经封装好了不少操做,自动管理cookie,session保持链接。咱们能够先访问某个目标网站,创建一个session链接以后,获取cookie。代码以下:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

运行结果以下:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

使用 requests.Session 会话对象让你可以跨请求保持某些参数,它也会在同一个 Session 实例发出的全部请求之间保持 cookie, 期间使用 urllib3 的 connection pooling 功能。详细内容参见requests高级用法:http://docs.python-requests.org/zh_CN/latest/user/advanced.html

由于 requests 模块不能执行 JavaScript,因此它不能处理不少新式的跟踪软件生成的 cookie,好比 Google Analytics,只有当客户端脚本执行后才设置 cookie(或者在用户浏览页面时基于网页事件产生 cookie,好比点击按钮)。要处理这些动做,须要用 Selenium 和 PhantomJS 包。

Selenium的安装已经在以前的文章中讲到,今天就说下PhantomJS吧。URL:http://phantomjs.org/ PhantomJS 是一个“无头”(headless)浏览器。它会把网站加载到内存并执行页面上的 JavaScript,但不会向用户展现网页的图形界面。将 Selenium 和 PhantomJS 结合在一块儿,就能够运行一个很是强大的网络爬虫了,能够处理 cookie、JavaScript、headers,以及任何你须要作的事情。

PhantomJS能够依据本身的开发平台选择不一样的包进行下载:http://phantomjs.org/download.html 解压即用,很方便。

接下来呢,仍是以实例出发,对 http://pythonscraping.com 网站调用 webdriver 的 get_cookie()方法来查看 cookie(D:/phantomjs-2.1.1-windows/bin/phantomjs.exe是个人PhantomJS路径,这里须要更改为你本身的):

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

这样就能够得到一个很是典型的 Google Analytics 的 cookie 列表:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

还能够调用 delete_cookie()、add_cookie() 和 delete_all_cookies() 方法来处理 cookie。另外,还能够保存 cookie 以备其余网络爬虫使用。

经过Selenium和PhantomJS,咱们能够很好的处理一些须要事件执行后才能得到的cookie。

2.3 正常的访问速度

有一些防御措施完备的网站可能会阻止你快速地提交表单,或者快速地与网站进行交互。即便没有这些安全措施,用一个比普通人快不少的速度从一个网站下载大量信息也可能让本身被网站封杀。

所以,虽然多进程程序多是一个快速加载页面的好办法——在一个进程中处理数据,另外一个进程中加载页面——可是这对编写好的爬虫来讲是恐怖的策略。仍是应该尽可能保证一次加载页面加载且数据请求最小化。若是条件容许,尽可能为每一个页面访问增长一点儿时间间隔,即便你要增长两行代码:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

合理控制速度是你不该该破坏的规则。过分消耗别人的服务器资源会让你置身于非法境地,更严重的是这么作可能会把一个小型网站拖垮甚至下线。拖垮网站是不道德的,是彻头彻尾的错误。因此请控制采集速度!

2.4 注意隐含输入字段

在 HTML 表单中,“隐含”字段可让字段的值对浏览器可见,可是对用户不可见(除非看网页源代码)。随着愈来愈多的网站开始用 cookie 存储状态变量来管理用户状态,在找到另外一个最佳用途以前,隐含字段主要用于阻止爬虫自动提交表单。

下图显示的例子就是 Facebook 登陆页面上的隐含字段。虽然表单里只有三个可见字段(username、password 和一个确认按钮),可是在源代码里表单会向服务器传送大量的信息。

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

用隐含字段阻止网络数据采集的方式主要有两种。第一种是表单页面上的一个字段能够用服务器生成的随机变量表示。若是提交时这个值不在表单处理页面上,服务器就有理由认为这个提交不是从原始表单页面上提交的,而是由一个网络机器人直接提交到表单处理页面的。绕开这个问题的最佳方法就是,首先采集表单所在页面上生成的随机变量,而后再提交到表单处理页面。

第二种方式是“蜜罐”(honey pot)。若是表单里包含一个具备普通名称的隐含字段(设置蜜罐圈套),好比“用户名”(username)或“邮箱地址”(email address),设计不太好的网络机器人每每无论这个字段是否是对用户可见,直接填写这个字段并向服务器提交,这样就会中服务器的蜜罐圈套。服务器会把全部隐含字段的真实值(或者与表单提交页面的默认值不一样的值)都忽略,并且填写隐含字段的访问用户也可能被网站封杀。

总之,有时检查表单所在的页面十分必要,看看有没有遗漏或弄错一些服务器预先设定好的隐含字段(蜜罐圈套)。若是你看到一些隐含字段,一般带有较大的随机字符串变量,那么极可能网络服务器会在表单提交的时候检查它们。另外,还有其余一些检查,用来保证这些当前生成的表单变量只被使用一次或是最近生成的(这样能够避免变量被简单地存储到一个程序中反复使用)。

2.5 爬虫如何避开蜜罐

虽然在进行网络数据采集时用 CSS 属性区分有用信息和无用信息会很容易(好比,经过读取 id和 class 标签获取信息),但这么作有时也会出问题。若是网络表单的一个字段经过 CSS 设置成对用户不可见,那么能够认为普通用户访问网站的时候不能填写这个字段,由于它没有显示在浏览器上。若是这个字段被填写了,就多是机器人干的,所以这个提交会失效。

这种手段不只能够应用在网站的表单上,还能够应用在连接、图片、文件,以及一些能够被机器人读取,但普通用户在浏览器上却看不到的任何内容上面。访问者若是访问了网站上的一个“隐含”内容,就会触发服务器脚本封杀这个用户的 IP 地址,把这个用户踢出网站,或者采起其余措施禁止这个用户接入网站。实际上,许多商业模式就是在干这些事情。

下面的例子所用的网页在 http://pythonscraping.com/pages/itsatrap.html,这是一个给咱们python爬虫学习的一个网站。这个页面包含了两个连接,一个经过 CSS 隐含了,另外一个是可见的。另外,页面上还包括两个隐含字段:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

这三个元素经过三种不一样的方式对用户隐藏:

  • 第一个连接是经过简单的 CSS 属性设置 display:none 进行隐藏;
  • 电话号码字段 name=”phone” 是一个隐含的输入字段;
  • 邮箱地址字段 name=”email” 是将元素向右移动 50 000 像素(应该会超出电脑显示器的边界)并隐藏滚动条。

由于 Selenium 能够获取访问页面的内容,因此它能够区分页面上的可见元素与隐含元素。经过 is_displayed() 能够判断元素在页面上是否可见。

例如,下面的代码示例就是获取前面那个页面的内容,而后查找隐含连接和隐含输入字段(一样,须要更改下PhantomJS路径):

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

Selenium 抓取出了每一个隐含的连接和字段,结果以下所示:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

虽然你不太可能会去访问你找到的那些隐含连接,可是在提交前,记得确认一下那些已经在表单中、准备提交的隐含字段的值(或者让 Selenium 为你自动提交)。

2.6 建立本身的代理IP池

启用远程平台的人一般有两个目的:对更大计算能力和灵活性的需求,以及对可变 IP 地址的需求。

有一些网站会设置访问阈值,也就是说,若是一个IP访问速度超过这个阈值,那么网站就会认为,这是一个爬虫程序,而不是用户行为。为了不远程服务器封锁IP,或者想加快爬取速度,一个可行的方法就是使用代理IP,咱们须要作的就是建立一个本身的代理IP池。

思路:经过免费IP代理网站爬取IP,构建一个容量为100的代理IP池。从代理IP池中随机选取IP,在使用IP以前,检查IP是否可用。若是可用,使用该IP访问目标页面,若是不可用,舍弃该IP。当代理IP池中IP的数量小于20的时候,更新整个代理IP池,即从新从免费IP代理网站爬取IP,构建一个新的容量为100的代理IP池。

仍是使用在以前笔记中提到过的西刺代理,URL:http://www.xicidaili.com/,若是想方便一些,可使用他们提供的API,直接获取IP。可是这些IP的更新速度有些慢,15分钟更新一次,若是知足需求,使用这个API无妨,若是需求得不到知足呢?呃…需求…不能知足…咳咳!

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

咱们能够本身爬取IP。可是,注意一点,千万不要爬太快!很容易被服务器Block哦!

好比,我想爬取国内高匿代理,第一页的URL为:www.xicidaili.com/nn/1,第二页的URL为:www.xicidaili.com/nn/2,其余页面一次类推,一页IP正好100个,够咱们用了。

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

经过审查元素可知,这些ip都存放在了id属性为ip_list的table中。

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

咱们可使用lxml的xpath和Beutifulsoup结合的方法,爬取全部的IP。固然,也可使用正则表达式,方法不少。代码以下:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

能够看到,经过这种方法,很容易的就得到了这100个IP,包括他们的协议、IP和端口号。这里我是用”#”符号隔开,使用以前,只须要spilt()方法,就能够提取出信息。

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

已经获取了IP,如何验证这个IP是否可用呢?一种方案是GET请求一个网页,设置timeout超市时间,若是超时服务器没有反应,说明IP不可用。这里的实现,能够参见Requests的高级用法:http://docs.python-requests.org/zh_CN/latest/user/advanced.html

这种设置timeout的验证方法是一种常见的方法,不少人都这样验证。因此博主就想了一个问题,有没有其余的方法呢?通过思考,想出了一个方法,测试了一个,验证一个IP大约须要3秒左右。呃..固然这种方法是我本身琢磨出来的,没有参考,因此,若是有错误之处,或者更好的方法,还望指正!

在Windows下,能够在CMD中输入以下指令查看IP的连通性(mac和linux能够在中断查看):

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

从免费代理网站得到的代理IP很不稳定,过几分钟再测试这个代理IP你可能会发现,这个IP已经不能用了。因此再使用代理IP以前,咱们须要测试下代理IP是否可用。

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

从上文可知,经过测试本机和代理IP地址的连通性,咱们可以大体知道这个代理 IP的健康状况。若是,本机可以ping通这个代理 IP,那么咱们也就可使用这个代理 IP去访问其余网站。这个过程是在cmd中执行的,那么python有没有提供一个方法,经过程序来实现这样的操做呢?答案是确定的,有!Subprocess.Popen()能够建立一个进程,当shell参数为true时,程序经过shell来执行:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

  • 参数args能够是字符串或者序列类型(如:list,元组),用于指定进程的可执行文件及其参数。若是是序列类型,第一个元素一般是可执行文件的路径。咱们也能够显式的使用executeable参数来指定可执行文件的路径。
  • 参数stdin, stdout,stderr分别表示程序的标准输入、输出、错误句柄。他们能够是PIPE,文件描述符或文件对象,也能够设置为None,表示从父进程继承。
  • 若是参数shell设为true,程序将经过shell来执行。
  • subprocess.PIPE:在建立Popen对象时,subprocess.PIPE能够初始化stdin,stdout或stderr参数。表示与子进程通讯的标准流。
  • subprocess.STDOUT:建立Popen对象时,用于初始化stderr参数,表示将错误经过标准输出流输出。
  • 了解到以上这些,咱们就能够写咱们的程序了(ping本机回环地址):

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

运行结果以下:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

能都获得返回结果,跟cmd中相似,接下来,咱们就能够制定相应的规则,根据返回信息来剔除不知足要求的ip。

总体代码以下:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

从上面代码能够看出,我制定的规则是,若是丢包数大于2个,则认为ip不能用。ping通的平均时间大于200ms也抛弃。固然,我这个要求有点严格,能够视状况放宽规则:

神级程序员:让你的爬虫就像人类的用户行为! 你敢封我IP吗?

从打印结果中能够看出,第一个随机选取的IP被抛弃了,第二个随机选取的IP能用。

我只是实现了,构建代理IP池和检查IP是否可用,若是你感兴趣也能够将获取的IP放入到数据库中,不过我没这样作,由于感受免费获取的代理IP,失效很快,随用随取就行。固然,也能够本身写代码试试reqeusts的GET请求,经过设置timeout参数来验证代理IP是否可用,由于方法简单,因此在此再也不累述。

除此以外,咱们也能够个建立一个User-Agent的列表,多罗列点。也是跟代理IP同样,每次访问随机选取一个。这样在必定程度上,也能避免被服务器封杀。

3 总结

若是你一直被网站封杀却找不到缘由,那么这里有个检查列表,能够帮你诊断一下问题出在哪里。

  • 首先,检查 JavaScript 。若是你从网络服务器收到的页面是空白的,缺乏信息,或其遇到他不符合你预期的状况(或者不是你在浏览器上看到的内容),有多是由于网站建立页面的 JavaScript 执行有问题。
  • 检查正常浏览器提交的参数。若是你准备向网站提交表单或发出 POST 请求,记得检查一下页面的内容,看看你想提交的每一个字段是否是都已经填好,并且格式也正确。用 Chrome 浏览器的网络面板(快捷键 F12 打开开发者控制台,而后点击“Network”便可看到)查看发送到网站的 POST 命令,确认你的每一个参数都是正确的。
  • 是否有合法的 Cookie?若是你已经登陆网站却不能保持登陆状态,或者网站上出现了其余的“登陆状态”异常,请检查你的 cookie。确认在加载每一个页面时 cookie 都被正确调用,并且你的 cookie 在每次发起请求时都发送到了网站上。
  • IP 被封禁?若是你在客户端遇到了 HTTP 错误,尤为是 403 禁止访问错误,这可能说明网站已经把你的 IP 看成机器人了,再也不接受你的任何请求。你要么等待你的 IP 地址从网站黑名单里移除,要么就换个 IP 地址。若是你肯定本身并无被封杀,那么再检查下面的内容:
    • 确认你的爬虫在网站上的速度不是特别快。快速采集是一种恶习,会对网管的服务器形成沉重的负担,还会让你陷入违法境地,也是 IP 被网站列入黑名单的首要缘由。给你的爬虫增长延迟,让它们在夜深人静的时候运行。切记:匆匆忙忙写程序或收集数据都是拙劣项目管理的表现;应该提早作好计划,避免临阵慌乱。
    • 还有一件必须作的事情:修改你的请求头!有些网站会封杀任何声称本身是爬虫的访问者。若是你不肯定请求头的值怎样才算合适,就用你本身浏览器的请求头吧。
    • 确认你没有点击或访问任何人类用户一般不能点击或接入的信息。
    • 若是你用了一大堆复杂的手段才接入网站,考虑联系一下网管吧,告诉他们你的目的。试试发邮件到 webmaster@< 域名 > 或 admin@< 域名 >,请求网管容许你使用爬虫采集数据。管理员也是人嘛!

使用免费的代理IP也是有局限的,就是不稳定。更好的方法是,花钱买一个能够动态切换IP的阿里云服务器,这样IP就能够无限动态变化了!

以上内容整理自《Python网络数据采集》,以及本身的一点当心得。重要的事情再说一遍:咱们在爬取别人网站的时候,也为对方考虑考虑!

相关文章
相关标签/搜索