最简单的反爬手段
有一部分网站(甚至包括部分商业网站)其实并没有真正认真做过反爬虫这件事情,你不需要做任何伪装,即可分分钟抓光它的网站。面对这样的网站,你只需要开大马力抓抓抓就好了,如果处于情怀考虑,你可以抓的慢一点,让它的服务器别太累。
除去这样的情况,最简单的反爬虫机制,应该算是U-A校验了。浏览器在发送请求的时候,会附带一部分浏览器及当前系统环境的参数给服务器,这部分数据放在HTTP请求的header部分。
通过访问频度反爬
这种反爬虫机制的原理是,真人通过浏览器访问网站的速度(相对程序来讲)是很慢的,所以如果你一秒访问了200个页面——这里不代表实际数值,只是表达在较短时间内发送了较多请求,具体阈值需要具体考虑——服务器则认为你是一个爬虫。
适用情况:限制频率情况。
Requests,Urllib2都可以使用time库的sleep()函数:
import time
time.sleep(1)
通过验证码限制
这样的方式与上面的方式相比更加难处理的是,不管你的访问频次怎么样,你都需要输入验证码才行。比如12306,不管你是登录还是购票,也不论你是第一次还是第一万次购买,你都需要输入一个验证码之后才能继续。这时候,在绝大部分情况下,你必须要想办法识别验证码了。之所以说是大多数情况下,是因为在极少数极少数情况下(尤其是政府网站),棒槌程序员通过客户端的JavaScript来校验验证码,这时候对你的爬虫来讲,其实是没有验证码的(比如中国商标网)。除开你遇到这种几乎可以忽略不计的棒槌开发的网站,其他时候你只有通过识别验证码来继续后面的操作了。
1、首先你可以找到验证吗图片的url
2、把图片保存到本地,然后手动输入验证码达到验证的效果,可以参考我前面的文章,有关豆瓣验证码的处理
通过经常变换网页结构
常见于一些社交网站,他们会经常更换网页的结构,如果你是通过依赖网页结构来解析需要的数据(不幸的是大部分情况下我们都需要通过网页结构来解析需要的数据),则在原本的网页位置找不到原本需要的内容。这时候,要分不同情况具体处理了。如果你只打算一次性抓取特定数据,那么赶快行动,它以后结构变了无所谓,反正你也不打算在抓它一次。如果是需要持续性抓取的网站,就要仔细思考下应对方案了。一个简单粗暴但是比较费力的办法是,写一个校验脚本,定期校验网页结构,如果与预期不符,那么赶快通知自己(或者特定开发者)修改解析部分,以应对网页结构变化。
对于Ajax请求的处理
对于“加载更多”情况,使用Ajax来传输很多数据。它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。
自动化测试工具Selenium
Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。
使用代理
适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
proxies = {'http':'http://XX.XX.XX.XX:XXXX'}
Requests://强烈推荐使用
import requests
response = requests.get(url=url, proxies=proxies)
Urllib2:
import urllib2
proxy_support = urllib2.ProxyHandler(proxies)
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象
response = urllib2.urlopen(url)
多线程
由于Python的是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块。
multiprocessing提供模块一个了Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束:
from multiprocessing import Process
import os
#子进程要执行的代码
def run_proc(name):
print 'Run child process %s (%s)...' % (name, os.getpid())
if __name__=='__main__':
print 'Parent process %s.' % os.getpid()
p = Process(target=run_proc, args=('test',))
print 'Process will start.'
p.start()
p.join()
print 'Process end.'
执行结果如下:
Parent process 928.
Process will start.
Run child process test (929)...
Process end.
参考 廖雪峰 的python教程