第三篇记录一下如何解决学习爬虫经常产生的IP的需求问题,时常苦苦搜寻,一个个复制粘贴测试是否可用甚是辛苦,突发奇想,尝试一劳多得,遂自己造个轮子,调用即可,岂不美哉,作为日常学习使用。
2020.5.26再次更新(添加了IPSearch_0使用方法)
项目已上传到GitHub:https://github.com/dataformydream/IPsearch
本文为IPSearch第一版本:IPSearch_0.py,可用来参考实现思路和学习总结。
申明:本文和相关代码只做学习用途,请合理合法使用。
目录
一、IP相关
二、功能需求
三、实现
思路
代码
使用方法
输出
暂只知道以下能获取到IP的途径:
1、付费:高匿,稳定(相对),调用接口省事,适合大规模爬虫,个人学习一般用不到。
2、免费:IP提供商收集的免费IP,当然大多不能用,需要自己筛选。
本篇暂选择了三个免费IP网站(国内)抓取IP,有些网站也提供了免费的调用接口,为练习爬虫还是直接爬取。
免费IP网站也有反爬措施和robot协议,建议遵守规则,详细阅读,控制访问频率,勿商用。
网站:西刺、西拉、高可用全球免费代理IP库
为了方便使用,将以下功能封装在一个py文件中:
1、封装通用的requests库get方法为一个函数,返回get结果,主要实现随机选取user-agent,随机选取IP,若IP被识别则更换重新爬取,直到爬取成功,同时删去IP池中被封的IP,维持IP池可靠可用。
2、headers和proxies作为全局变量调用,headers可灵活添加xm-sign,referer,cookies等参数(即可变字典),IP池proxies为不重复列表
3、通过有限的IP或本机地址,抓取免费IP网站,对可用IP进行筛选,筛选条件可为类型(高匿透明等),IP类型(http、https)、响应速度、存活时间。筛选后存入IP池。(数据来源于IP网站)
4、能针对特定的网站对IP池进行筛选,维护IP池对爬虫网站访问的稳定高效,借此提高抓取效率,而不是网站用来检测是否可用的百度等首页。(能访问百度不一定能爬要爬的网站)
5、要获取的IP数可选(没有上限,数目不够自动遍历网站更多页面,甚至可爬光IP网站所有IP列表页面,不过时间极长,极不推荐,给网站服务器造成不必要的负担,甚至可能有法律风险,一般学习用爬虫10到20个IP足够了),并能在当前爬虫程序目录下生成json文件保存可用IP列表(只要能通过4中的筛选一般不会失效,生成后下次运行爬虫直接调用进IP池,会提前筛选一次,不够设定数目才会请求IP网站,大大减少重复获取IP时间)
暂未实现功能:
1、测试IP是否可用的函数的多线程实现(本质为request请求,IO密集型,可大幅提高效率)
2、IP池的存储方式的优化,由本地的json文件改为数据库存储
3、支持更多的免费IP网站,暂只实现了三个网站,且IP范围限制在国内。
第一步:分析三个网站,从IP网站抓取最新可用IP并筛选(网站会定时地检测和排序,最新的一般都在前几页,从前往后获取即可)
第二步:对筛选后的IP列表用要爬的网站地址进行测试访问,删去访问失败或速度较慢的。
第三步、主函数调用各函数,实现本地导入导出、显示和统计、IP数设置、自动检测和补充IP、网页遍历等功能。
文件名:IPSearch.py 第一版本为 IPSearch_0.py
这里只贴出如何获取网站免费IP的爬虫代码,完整代码请访问开头GitHub链接。
#!user/bin/env python
# -*- encoding=utf-8 -*-
import os
import requests
from lxml import etree
import json
import random
# 单独的请求西刺网站
def get_xici(url):
pro_list = list()
response = get_response(url).text
pro_htmls = etree.HTML(response).xpath("//tr[@class]")
for num in pro_htmls:
ip = num.xpath('./td[2]/text()')[0]
port = num.xpath('./td[3]/text()')[0]
types = num.xpath('./td[5]/text()')[0]
type_url = num.xpath('./td[6]/text()')[0].lower()
speed = float(num.xpath('.//div[@class="bar"]')[0].xpath('./@title')[0].replace('秒', ''))
connect_speed = float(num.xpath('.//div[@class="bar"]')[1].xpath('./@title')[0].replace('秒', ''))
life = num.xpath('./td[last()-1]/text()')[0]
if types == '高匿' and speed < 2 and connect_speed < 1 and '天' in life or '小时' in life: # 筛选条件,可自己添加
pro = type_url + '://' + ip + ':' + port
# print(pro)
pro_list.append(pro)
print(pro_list)
print(len(pro_list))
return pro_list
# 单独的请求西拉网站
def get_xila(url):
pro_list = []
response = get_response(url).text
pro_htmls = etree.HTML(response).xpath("//tbody/tr")
for num in pro_htmls:
ip = num.xpath('./td[1]/text()')[0]
types = num.xpath('./td[3]/text()')[0]
type_url = num.xpath('./td[2]/text()')[0].replace('代理', '').lower()
if 'https' in type_url:
type_url = 'https'
speed = float(num.xpath('./td[5]/text()')[0])
life = num.xpath('./td[6]/text()')[0]
score = int(num.xpath('./td[last()]/text()')[0])
if '高匿' in types and speed < 3 or '天' in life and score > 10: # 筛选条件,可自己添加
pro = type_url + '://' + ip
pro_list.append(pro)
print(pro_list)
print(len(pro_list))
return pro_list
# 单独的请求免费代理库网站
def get_mianfei(url):
pro_list = list()
response = get_response(url).text
pro_htmls = etree.HTML(response).xpath("//tbody/tr")
for num in pro_htmls:
ip = num.xpath('./td[1]/text()')[0]
port = num.xpath('./td[2]/text()')[0]
types = num.xpath('./td[3]/text()')[0]
type_url = num.xpath('./td[4]/text()')[0].lower()
speed = num.xpath('./td[8]/text()')[0]
if '毫秒' in speed:
speed = float(speed.replace('毫秒', '')) / 1000
else:
speed = float(speed.replace('秒', ''))
life = num.xpath('./td[last()-2]/text()')[0]
if types == '高匿' and speed < 2 and '天' in life or '小时' in life: # 筛选条件,可自己添加
pro = type_url + '://' + ip + ':' + port
# print(pro)
pro_list.append(pro)
print(pro_list)
print(len(pro_list))
return pro_list
if __name__ == "__main__":
search_proxies('https://www.ximalaya.com/', 20)
1、引用
from IPSearch_0 import *
或者
from IPSearch_0 import proxies,header_add,get_response,add_test,search_proxies
2、各变量用途和用法
proxies
全局变量,代理池,列表类型,如:[ip1,ip2,ip3,...],初始为空。
header_add
和请求头的设置有关,默认headers中只有随机选取的"User-Agent"这一项,要添加更多参数如下:
from xm_sign import get_sign # 要传入headers的函数
# 将要添加的参数新建键值对传入header_add
# 同时支持变量和函数传入,注意:传入函数时传入的是函数名get_sign,而不是函数get_sign()
header_add['xm-sign']=get_sign
header_add['Referer']='https://www.ximalaya.com/'
get_response(url)
封装后的request.get()函数,实现随机user-agent,随机proxies请求网页,若proxies为空则使用本地IP,若IP失效则从proxies中删去,直到请求成功为止。
输入:要请求网页的URL,返回值:request.get()返回类型,可用r.text,r.content等
header_add['xm-sign']=get_sign
header_add['Referer']='https://www.ximalaya.com/'
# ----------------之前需要设置好添加的headers内容,get_response内部调用-----------------------
# get_response(url) 传入要爬取的网站即可,在函数内部实现代理的随机选取、
# 同时支持http和https代理、while语句保证请求成功和删除失效代理等
response = get_response('https://www.ximalaya.com/category/')
# 函数返回值即为requests.get()返回类型
print(response.text)
print(response.content)
print(response.status_code)
print(response.request.headers)
add_test(url,test_list=None)
用来检测test_list中的代理,是否对URL可用(能否请求成功),可用则添加进proxies,若没有要检测的ip池可忽略。
输出:无,函数直接对proxies进行操作,同时新的proxies覆盖到本地json文件保存(ip.json,项目文件夹中生成)
test_list=[ip1,ip2,ip3,.....]
# 测试test_list中ip是否可用并更新到proxies
add_test('http://www.baidu.com',test_list)
# 测试proxies中ip是否仍有效,不指定test_list
add_test('http://www.baidu.com')
search_proxies(url,need_number=30,test_flag=True)
主函数,输入为要爬取网站的URL,需要的ip数量的最小值,test_flag为True时,本地之前保存的ip重新测试,为False时不测试,直接传入proxies
实现功能:
1、导入本地已有json测试并导入proxies。
2、文件数判断,获取ip到满足设置的need_number为止。
3、更新proxies和本地json文件
完整使用方法:
# 喜马拉雅获取xm_sign 的引用,get_sign()函数
from xm_sign import get_sign
from IPSearch_0 import proxies, header_add, get_response, add_test, search_proxies
header_add['xm-sign'] = get_sign
header_add['Referer'] = 'https://www.ximalaya.com/'
print(header_add)
search_proxies('https://www.ximalaya.com/', 20)
print(proxies)
'''
在此调用get_response()实现爬虫程序
response = get_response('https://www.ximalaya.com/category/')
# 可实时调用,补充代理池
search_proxies('https://www.ximalaya.com/', 100)
'''
{'xm-sign': , 'Referer': 'https://www.ximalaya.com/'}
获取代理中...
未发现本地IP文件,从免费代理网站重新获取...
离要求的IP数还差20个,从免费代理网站开始获取
获取中:西刺
无代理,使用本机IP
西刺获取成功,共有38个IP
开始验证对爬取网站https://www.ximalaya.com/的有效性,时间较长,请等待...
[---------------ip 列表(已省略)-------------]
IP适用,已保存
IP适用,已保存
IP适用,已保存
已删去请求失败IP
IP适用,已保存
---------检测日志(已省略)-----------------------
已删去请求失败IP
已删去请求失败IP
IP适用,已保存
已删去请求失败IP
测试完成,适用IP已添加到proxies
proxies已有ip为26个。
代理获取完毕,最终获取到26个可用代理,已写入本地。
因为爬取的IP以页为单位批量爬取,所以实际获取到的可能是大于要求的,大概是以30到40为一个区间,search_proxies也可在函数内部做检测IP池用,调用一次即可。
获取IP中...
已导入本地备份
开始验证对爬取网站的有效性,时间较长,请等待...
IP适用,已保存
IP适用,已保存
IP适用,已保存
IP适用,已保存
.............略过...........
IP适用,已保存
已删去请求失败IP。
本地请求成功IP为42个。
本地IP数已达到要求,暂不请求网站获取IP。