第5章


IP代理




对于采取了比较强的反爬措施网站来说,要想顺利爬取网站数据,设置随机 Useragent 和IP代理是非常有效的两个方法。


图5.1频繁爬取之后

代理就是换个身份,网络中的身份之一就是IP。在爬虫中,有些网站可能为了防止爬虫或者DDoS等,会记录每个IP的访问次数。比如,有些网站允许一个IP在1s内只能访问10次等,那么就需要访问一次换一个IP。如果不对IP做任何设置,频繁访问网站之后,网站就可能会出现图5.1的提示。使用IP代理可以解除被封IP这种反爬机制。
IP代理的获取,可以从以下几个途径得到: 
(1) 从免费的网站上获取,但质量很低,能用的IP极少; 
(2) 购买收费的代理服务,质量高很多; 
(3) 自己搭建代理服务器,虽然稳定,但需要大量的服务器资源。
5.1IP代理的作用
(1) 可以突破自身IP的限制,访问一些不许访问的站点; 
(2) 隐藏自身真实IP,以免被封锁。
如果想查看本机的IP,可以有多种方式,下面提供两种简单的查看本机IP的方法。
【例51】查看本机IP。
方法1: 在百度输入IP看到的就是本机IP,如图5.2所示。


图5.2查看本机IP


方法2: 通过程序查看,代码实现如下: 

import requests

url = 'http://icanhazip.com'

try:

response = requests.get(url) #不使用代理

print(response.status_code)

if response.status_code == 200:

print(response.text)

except requests.ConnectionError as e:

print(e.args)

程序执行的结果如下: 

200

123.123.40.xxx  #后三位隐去了

5.2IP代理使用方法
常见的代理包括 HTTP 代理和 SOCKS5 代理,这里主要介绍HTTP代理。HTTP可以在网上搜索一些免费的IP代理进行测试。然后在Requests请求方法加入一个参数proxies={字典}实现对IP代理的使用,其中字典的键名是 HTTP或者HTTPS,键对应的值为一个IP地址。
例如proxies={'http':'59.120.117.244'},其中键名“http”表示协议类型,键值“59.120.117.244”表示代理。
如果请求URL使用的是 HTTP协议,那么就使用 HTTP代理; 如果请求URL使用的是HTTPS,就使用HTTPS代理。
【例52】设置IP代理爬取百度首页,代码如下: 

import requests

url="http://www.baidu.com/s"

headers={    

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'}

response=requests.get(url=url,headers=headers, proxies={'http':'59.120.117.244'})

with open('baidu.html','w',encoding='utf-8')as fp:

fp.write(response.text)

5.3搭建IP池
在爬虫过程中,使用本地IP频繁爬取某个网站后,可能会导致IP被封,因此有必要搭建一个IP池。
【例53】搭建一个免费的IP池。
【解析】爬取快代理网站上的免费IP,链接如下:
“https://www.kuaidaili.com/free/”
5.3.1获取单页IP
首先定义一个获取目标网页的方法,爬取目标网页如图5.3所示,解析出该目标页的HTTP、PORT、IP。


图5.3待解析的目标网页


操作步骤如下:
第一步: 查看Network面板,找到目标数据所在请求资源文件的Headers,如图5.4所示,对Request URL发送GET请求,获得网页数据。


图5.4查看目标数据的Headers


第二步: 解析网页数据,获得PORT、IP和协议类型。
代码如下:

from lxml import etree

def get_content(url):

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'}#加载伪装头防止反爬

response = requests.get(url,headers=headers)

if response.status_code == 200:

print('连接正常')

html =etree.HTML(response.text)

IP=html.xpath('//td[@data-title="IP"]/text()')

PORT=html.xpath('//td[@data-title="PORT"]/text()')

TYPE=html.xpath( '//td[@data-title="类型"]/text()')

return IP,PORT,TYPE

else:

print('连接失败或遭遇反爬')

5.3.2获取多页IP
对获取的IP、PORT和协议类型封装成键值对的字典格式,并存储在字典列表中,已备监测可用性使用,代码实现如下: 

import time

diclist=[]

def get_url(page):#传入的数据是爬取目标网页的页数

for i in range(int(page)):

try:

print('正在爬取第%d页'%(i+1))

url = 'https://www.kuaidaili.com/free/inha/{}/'.format(i+1)

print("爬取网址为:",url)

IP,PORT,TYPE=get_content(url)#这是一个自定义解析网页内容的方法

for i in range(len(IP)):               

dic={}

dic[TYPE[i]]=IP[i]+':'+PORT[i]                

diclist.append(dic)

time.sleep(3)#防止访问频率过快,被封

except Exception as e:

print('爬取失败',e)

调用该方法之后程序执行结果如图5.5所示。


图5.5得到IP地址


5.3.3检测IP有效性 
利用百度网页进行检测,将IP传入proxies参数中去验证,如果在规定的时间内返回的state_code = 200,就说明IP是有效的,否则就报错,代码实现如下: 

def check_ip(reg):#网上检查IP的有效性

url = 'https://www.baidu.com/'

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'}

can_use = []

for i in reg:

try:

response = requests.get(url,headers,proxies = i,timeout = 1)

if response.status_code == 200:

can_use.append(i)

except Exception as e:

print('出现问题',e)

return can_use

5.3.4建立IP池
把检测有效的IP地址存储之后,就有了一个IP池,以备后续在爬取程序的时候,可以随机使用自己建立的IP池中的IP地址,代码如下:

can_ip=check_ip(diclist)

def save_ip(can_ip):

with open('ip.txt','w+') as f:

for i in data:

f.write(str(i)+'\n')

f.close()

5.4付费IP代理使用
免费的 IP 往往效果不是很好,可以搭建 IP 代理池,但是搭建一个 IP 代理池成本很高,如果只是个人平时偶尔使用一下爬虫,也可以考虑付费 IP,几块钱买个几小时动态 IP,多数情况下都足够爬一个网站了。这里推荐一个付费代理“阿布云”代理。
“阿布云”代理网址: https://www.abuyun.com/httpproxy/dynmanualpython.html,代码实现如下:

import requests

# 要访问的目标页面

targetUrl = "http://test.abuyun.com"

#targetUrl = "http://proxy.abuyun.com/switch-ip"

#targetUrl = "http://proxy.abuyun.com/current-ip"

# 代理服务器

proxyHost = "http-dyn.abuyun.com"

proxyPort = "9020"

# 代理隧道验证信息

proxyUser = "H01234567890123D"

proxyPass = "0123456789012345"

proxyMeta = "http://%(user)s:%(pass)s@%(host)s:%(port)s" % {

"host" : proxyHost,

"port" : proxyPort,

"user" : proxyUser,

"pass" : proxyPass,

}

proxies = {

"http"  : proxyMeta,

"https" : proxyMeta,

}

resp = requests.get(targetUrl, proxies=proxies)

print (resp.status_code)

print( resp.text)

首次使用的话,可以选择购买一个小时的动态版试用,单击生成隧道代理信息作为凭证加入代码中即可。