爬取maitian屡次被封,先建立一个免费代理ip池吧
暂时保存为txt格式
思路:
1、找到免费的ip代理网站
以西刺代理的4个网站为例:
国内普通代理: http://www.xicidaili.com/nt/
国内高匿代理: http://www.xicidaili.com/nn/
国内https代理:http://www.xicidaili.com/wn/
国外http代理: http://www.xicidaili.com/wt/
2、使用requests框架多线程方式爬取
①添加user-agent池;
②4种类型的ip代理网站,每个网站多页爬取,创建线程池,每页为一个线程;
3、使用xpath解析
4、验证获取ip的有效性
5、仅保存有效ip 6、查看一共保存了多个有效ip,计算爬取时间
理清思路开始操作:
import requests
import random
from lxml import etree
import time
from threading import Thread
为了锻炼自己养成好习惯,这里封装一个ip爬取类
class IpSpider(object):
def __init__(self,path):
#指定文件保存路径
self.path = path
反爬的第一步:添加请求头,创建一个请求头列表,方便获取
def get_headers(self):
ug_list = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"]
#调用random方法,随机选取一个user-agent
ug = random.choice(ug_list)
#将选好的ug添加到请求头里
headers = {'User-Agent':ug}
return headers
获取ip的类方法:
def get_ip(self,ip_type,pagenum):
#创建url列表
url_list = ['http://www.xicidaili.com/nt/', # xicidaili国内普通代理
'http://www.xicidaili.com/nn/', # xicidaili国内高匿代理
'http://www.xicidaili.com/wn/', # xicidaili国内https代理
'http://www.xicidaili.com/wt/'] # xicidaili国外http代理
#4个类型的网站+多页,拼接url
#ip_type是类型的index,pagenum是页码
url = url_list[ip_type] + str(pagenum)
#获取请求头
headers = self.get_headers()
#传入url和headers发送request请求,获取响应体
response = requests.get(url,headers=headers,timeout=5).text
#对获取到的数据进行转译,以便提供给xpath进行解析
data = etree.HTML(response)
#分析网页,每行一个ip地址,使用xpath获取整页中所有包含ip数据的标签列表
all = data.xpath('.//table[@id="ip_list"]//tr')
#遍历得到的列表,去掉表头(表头无数据)
for i in all[1:]:
#获取host
host = i.xpath('./td[2]/text()')[0]
#获取port
port = i .xpath('./td[3]/text()')[0]
#拼接得到一个ip地址
ip = host + ':' + port
#print(ip)
#验证ip地址是否有效果,调用check_ip方法
is_avali = self.check_ip(ip)
#使用if语句
if is_avali:
#若返回True,则调用save_ip函数保存ip
self.save_ip(ip)
#print(ip,'有效')
#else:
#print(ip,'无效')
#返回False可以跳过不管
验证ip有效性的类方法:
def check_ip(self,ip):
headers = self.get_headers()
#使用百度作为验证网页,用来验证获取的是否为有效ip
check_url = 'https://www.baidu.com'
#构建proxies参数,这里因为以四个不同类型网站为例,不确定获取的是哪种类型的ip
#需要判断ip类型,requests框架中,可以自动识别ip类型
proxies = {'http':ip,'https':ip}
#为了避免报错中断,使用try—except语句
try:
response = requests.get(url=check_url,
headers=headers,
proxies=proxies,
timeout=30)
#布尔值判断,若请求成功返回True
return response.status_code == 200
except:
return False
#请求失败返回False
保存有效ip
def save_ip(self,ip):
#保存有效ip到指定路径
with open(self.path,'a',encoding='utf-8') as f:
f.write(ip +'\n')
#创建一个file,使用增加数据模式保存ip,每保存一个ip,进行换行
统计ip数量:
def ip_count(self):
#从指定路径读取ip个数
with open(self.path,'r',encoding='utf-8')as f:
ip_list = f.readlines()
#按行读取ip数据,获得一个ip列表,计算列表长度即获取的ip数量
count = len(ip_list)
return count
创建线程池,统筹调用多线程爬取:
def start(self):
#程序运行
#创建一个开始的时间
start = time.time()
#创建一个线程池,方便开启和阻塞线程
threds=[]
#创建线程,4个ip_type的网站,每个网站获取前三页,创建4*3个线程执行get_ip
for ip_type in range(4):
for pagenum in range(3):
t = Thread(target=self.get_ip,args=(ip_type,pagenum))
#放入线程池
threds.append(t)
print('开始爬取ip代理')
#开启线程
for i in threds:
i.start()
#阻塞线程,防止主程序提前结束
for i in threds:
i.join()
print('爬取完成')
#记录结束时间
end = time.time()
#检查共耗时多久
time_consuming = end - start
#获取ip数量
ip_count = self.ip_count()
print('共获取有效代理ip: %s 个,耗时:%s' % (ip_count,time_consuming))
最后一步,指定保存路径,可以开始运行啦
if __name__ == '__main__':
path = './ip_list_0920.txt'
IpSpider(path).start()
总结:
比较初级的ip获取保存方式,没有使用数据库,保存在txt格式中,使用代理池时,调用readlines方式逐行读取ip,免费ip的存活率很低,有需要的话尽量使用付费ip吧^^