我们在做爬虫的过程中经常会遇到这样的情况:最初爬虫正常运行,正常抓取数据,一切看起来都是那么美好,然而一杯茶的功夫可能就会出现错误,比如403Forbidden;这时候网页上可能会出现
“您的IP访问频率太高”这样的提示,或者跳出一个验证码让我们输入,之后才可能解封,但是一会之后又出现这种情况。
出现这个现象的原因是网站采取了一些反爬虫的措施。比如,服务器会检测某个IP在单位时间内的请求次数,如果超过了某个阀值,那么服务器会直接拒绝服务,返回一些错误信息。这种情况可以称为封IP,于是乎网站就成功把我们的爬虫禁掉了。
试想一下,既然服务器检测的是某个IP单位时间的请求次数,那么我们借助某种方式来伪装IP,让服务器无法识别由我们本机发起的请求,这样不就可以成功防止封IP了吗?
所以这时候代理就派上用场了。本章会详细介绍代理的基本知识及各种代理的使用方式,包括代理的设置、代理池的维护、付费代理的使用、ADSL拨号代理的搭建方法等内容,以帮助爬虫脱离封IP的“苦海”。
我们了解了利用代理可以解决目标网站封IP的问题。在网上有大量公开的免费代理,或者我们也可以购买付费的代理IP,但是代理不论是免费的还是付费的,都不能保证都是可用的,因为可能此IP被其他人使用来爬取同样的目标站点而被封禁,或者代理服务器突然发生故障或网络繁忙。
一旦我们选用了一个不可用的代理,这势必会影响爬虫的工作效率。
所以,我们需要提前做筛选,将不可用的代理剔除掉,保留可用代理。接下来我们就爬取西刺代理的免费代理进行验证然后存到本地搭建一个高效易用的代理池。
首先我们要发送请求获取西刺源码,
这里要注意的是西刺网站也有自己的反爬机制,记得把referer放进请求头
然后编写整个请求代码
def get_html():
# for x in range(2, 5):
url ={
'Remote Address': '123.57.85.224: 443',
'Connection': 'keep - alive',
'Host': 'www.xicidaili.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
}
response =requests.get(url, headers=header, timeout=20)
get_proxy(response.text)
资源爬取之后我们对页面使用xpath进行解析,得到网页中的ip代理,我们只取ip地址和端口
看如下代码
# 解析网页,并得到网页中的IP代理
def get_proxy(html):
selector =etree.HTML(html)
proxies =[]
foreach inselector.xpath("//tr[@class='odd']"):
ip =each.xpath("./td[2]/text()")[0]
port =each.xpath("./td[3]/text()")[0]
# 拼接IP地址,端口号
proxy =ip + ":" +port
proxies.append(proxy)
print(len(proxies))
紧接着把代理都爬取下来之后再对其进行验证是否有效
def test_proxy(proxy):
url ={
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
}
try:
response =requests.get(
url, headers=header, proxies={"http":proxy}, timeout=1)
ifresponse.status_code ==200:
print("该代理IP可用:", proxy)
thread_write_proxy(proxy)
else:
print("该代理IP不可用:", proxy)
exceptException:
print("该代理IP无效:", proxy)
pass
看结果:
验证完成之后把可用的代理保存到本地文件中
def thread_write_proxy(proxy):
withopen("./ip_proxy.txt", 'a+') asf:
print("正在写入:", proxy)
f.write(proxy+ '\n')
print("录入完成!!!")
这样搭建好了我们的一个代理池,以后需要的时候直接使用这些代理就可以了。我们还可以对程序进行一个改进,在验证IP是否可用的程序是串行的,因此只能验证一个结束后,才进行验证下一个,效率极低,我们可以把它改成多线程,提高我们的一个效率。
def thread_test_proxies(proxies):
proxies =proxies
# print("test_proxies函数开始运行。。。\n", proxies)
forproxy inproxies:
test =threading.Thread(target=test_proxy, args=(proxy,))
test.start()