第5章 IP代理 对于采取了比较强的反爬措施网站来说,要想顺利爬取网站数据,设置随机 Useragent 和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的方法。 【例51】查看本机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代理。 【例52】设置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池。 【例53】搭建一个免费的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/httpproxy/dynmanualpython.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) 首次使用的话,可以选择购买一个小时的动态版试用,单击生成隧道代理信息作为凭证加入代码中即可。