在爬虫时,我们不可避免的会遇到网页的反爬封锁,所以就有了爬虫的攻防,在攻和守之间两股力量不断的抗衡。接下来就讲讲我在爬虫时遇到的一些问题,以及解决的方法。
第一种:封锁user-agent破解
user-agent时浏览器的身份标识,网站就是通过user-agent来确定浏览器类型的。当我们在请求时发现,通过get函数发送的请求返回的内容与在PC浏览器检查的不一样。就可以首先考虑在get函数下的headers属性,把user-agent字段值构造成字典,添加给headers属性。例如:
#简单表示只模拟User-Agent部分
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64)\
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
然后用requests.get(url, headers = headers)
进行请求,这种方法可以满足部门网页的请求,可以作为遇到问题的第一种尝试。
第二种封锁user-agent的方法就是,携带cookies一些赋给Headers值,把Repuest Headers下的信息都构造成字典,赋给headers属性:
利用以上信息构造成字典:
#复杂表示,因为爬取过程中发现只用User-Agent部分仍然会被防火墙阻挡
request_headers = {
'Accept':'text/html, */*; q=0.01',
'Accept-Encoding':'gzip, deflate',
'Accept-Language':'zh-CN,zh;q=0.9',
'Connection':'keep-alive',
'Cookie':'acw_tc=AQAAAAFSbEV6igQAU3joKmb1pHb7Amkd;_umdata=2BA477700510A7DF4059C61C78E8395939FAD577E94352328D751D6CD84A71DC483C7165B9EADDACCD43AD3E795C914C9155FE5460049F4934F91027D34B6E6F;PHPSESSID=lrcjhpkrjtbffirbtch8hrh9g2;hasShow=1;UM_distinctid=1616afff050228-00a2c5f077a432-3b60490d-144000-1616afff052387;CNZZDATA1254842228=1796631317-1517916172-%7C1517916172;_uab_collina=151791861517128939720221;zg_did=%7B%22did%22%3A%20%221616afff15d69f-06e4c98572085c-3b60490d-144000-1616afff15e48b%22%7D;zg_de1d1a35bfa24ce29bbf2c7eb17e6c4f=%7B%22sid%22%3A%201517918613857%2C%22updated%22%3A%201517918631284%2C%22info%22%3A%201517918613860%2C%22superProperty%22%3A%20%22%7B%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%228731ad9f297a7dbbcff0814343e06ea3%22%7D;',
'Host':'www.qichacha.com',
'Referer':'http://www.qichacha.com/firm_06396efe66551d4ac07ee8cb41b0e325.html',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36',
'X-Requested-With':'XMLHttpRequest'
}
这种携带cookie值得headers一般用于需要登录才能获取部分信息的网页。
第二种:封锁间隔时间破解
通常对于某些网站,在我们发送请求后,因为访问速度过快,网页会很快发现我们的IP地址在一段时间内,多次像页面发送请求。对于一般的网站,它的反爬技术很可能就是利用公式计算某一IP地址在一段时间内发送请求的次数,因为一个正常人,在一定时间的请求都是有限的。
所以,对于这种情况,我们可以简单的尝试在爬虫的过程中,对我们的程序进行适当的延时,调用time.sleep()函数。这样既不会过快的访问网页,对对方的服务器产生严重的垃圾和负担,也可以防止程序被迫中止。
举一个例子就是,当初我们尝试封锁IP破解的时候(接下来我说到),我找到了一个免费代理IP的地址,于是我就要想办法批量的把IP地址爬下来,然后在进行测试,因为免费的代理IP大都性能不好或者已经不能用了。这个时候当我第一次爬的时候,没有爬完一页程序就被迫中止了,(因为返回的页面内容变了),我就知道遇到了反爬,那么我首先尝试的就是利用时间延时,方法就是调用time.sleep()函数,并把延迟时间定为3s,没想到程序就顺利运行了,成功的爬了10页的代理IP地址。
所以在遇到反爬时,如果你觉得你访问的页面是一般网站,不是那种存着比较重要信息的网站,可以首先尝试利用时间延时。
第三种:封锁IP破解
对于一些保存重要信息的网站,它的反爬技术会比较严密,它会严苛检查每一个IP的请求操作,然后对于可能是异常的请求,返回某一页面给对应请求或是提示需要登录信息等等甚至可能把相应的IP拉入黑名单。
这个时候我们可能就需要代理IP来隐藏我们的身份,以及通过更换IP来达到不断爬取数据的目的。
那么这些代理IP要从哪儿获取呢?如果你百度,其实会有蛮多免费代理IP的网站,里面会有很多的代理IP,但是不要太开心,因为这里的代理IP大都不稳定甚至失效(不然为什么那么多都要钱呢),所以当你批量爬下来代理IP后,还需要再单独写一个程序,去利用每一个IP请求一个一定有的网站,例如百度,如果这个IP的requests.get(‘http://www.baidu.com‘, proxies = proxy)(这里的proxy就是你的IP地址)访问成功了,才能说明这个IP是可用的。
这里介绍几个免费代理IP的网站:
快代理
大象代理
三一代理
当然,如果经济条件比较宽裕的,可以尝试去购买套餐,因为这样得IP会稳定很多,我自己对于免费IP的处理真的是很头疼,有些在你测试成功了之后,当你访问你需要请求的网站时,还是会报错。最后我还是买了套餐进行测试,所以说有钱真的能省很多事。
几个比较好的付费IP代理地址
云连代理IP
八爪鱼-大数据
如果你是通过免费代理IP爬取下来的IP地址,那么使用的时候就需要用到get函数的proxies属性
并不要把你获得的IP地址和端口号以这样的方式表示出来:
proxies = {
"http": "http://10.10.1.10:3128",
"https": "http://10.10.1.10:1080",
}
requests.get("http://example.org", proxies=proxies)
其中,"http": "http://10.10.1.10:3128"
是用来对http构成的网页进行请求时的代理,而"https": "http://10.10.1.10:1080"
是用来对https构成的网页进行请求时的代理,所以在使用时,如果发现设置的代理没有起作用,有可能就是你就http的网页运用了Https的代理或者反之,可以留意一下。
如果我们想知道设了了proxies属性后的get请求到底有没有携带我们设置的IP地址去请求,可以通过一下方法:
import requests
proxy = {'http': 'http://221.214.224.150:8888'}
r = requests.get('http://ip.cip.cc/', proxies = proxy)
print(r.text)
因为代码段中的网页就是用来返回本机IP地址的。
如果是爬免费的话,最好能爬高匿的IP,因为这样的IP的隐匿性更好,不会暴露你的一些电脑信息也会比较好的隐匿访问时携带的Cookie值(一些网站可能也会查Cookie值来做反爬技术)
如果你是付费购买套餐的话,就会方便很多。因为第一,一般付费后拿到的IP都比较稳定,第二就是一般那些网站都会有自己的软件,它们可以在运行的时候后台帮你切换IP地址,所以就不用专门构造IP地址赋值给proxies属性。这时候如果你想知道IP地址有没有切换,最简单的方法就是,直接在百度下搜索‘IP’,就可以显示你现在本机的IP地址了:
如果显示的跟你本机的不一样,就说明切换成功了,就可以不断的在后台切换IP地址进行爬虫了。
当然,付费的IP地址也不是说一定都很好,每一个都能用,因为也不仅仅是你一个人在用对吧,所以还是可能会遇到IP不稳定会断网的可能性,所以在我们的程序中,最后能设置一个循环,利用try…except….去捕获因为IP不稳定所造成的requests.get的请求错误,然后不断循环直到get方法请求成功。这里提供一个我做的时候的示例代码,应用时可以根据自己的实际情况使用:
以下这些循环都是为了在遇到网页请求错误或是网页需要验证的时候
先暂停运行,等待后台IP地址的转换,知道可以访问目标网页为止
在遇到错误等待时可能会限制了速度,但是保证了程序可以一直运行
'''
while True:
try:
#一下except都是用来捕获当requests请求出现异常时,
# 通过捕获然后等待网络情况的变化,以此来保护程序的不间断运行
req = requests.get(company_url, headers = headers, timeout = 20)
break
except requests.exceptions.ConnectionError:
print('ConnectionError -- please wait 3 seconds')
time.sleep(3)
except requests.exceptions.ChunkedEncodingError:
print('ChunkedEncodingError -- please wait 3 seconds')
time.sleep(3)
except:
print('Unfortunitely -- An Unknow Error Happened, Please wait 3 seconds')
time.sleep(3)
一般利用切换IP地址之后,就可以去爬大部分的网站了,如果一些更高级更安全的网站,现在没有遇到可能今后在遇到了,如果能成功再做记录吧~希望能给看完的各位提供一点解决问题上的思路