爬虫学习日记3-构建免费代理池
学习目标:工作中许多指标数据来源自多个网站,而且由于开发厂家不同,这些系统数据网站没有整合。由于各种原因,我只能拿到其中一小部分API接口,剩余大量数据需要手动下载。所以学习爬虫技术增加工作里的自动化程度,减少人力成本。
这两天主要完成了两个学习任务,当然大部分时间都用在钻研构建代理池了。
一、学习任务a: 安装selenium并学习
-
安装selenium并学习。
-
使用selenium模拟登陆163邮箱。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import userInfo #处于保密性考虑,邮箱名称和密码从文件里导入
user = userInfo.user
pwd = userInfo.pwd
browser = webdriver.Chrome() #实例化一个Chrome浏览器对象
browser.get("https://mail.163.com/")
browser.switch_to_frame(0) #不进入字frame无法进入登录界面,frame id为动态的,不能靠id获取
wait = WebDriverWait(browser,20) #引入一个WebDriverWait对象,timeout设为20s
# browser.implicitly_wait(10)
# 调用until方法,传入要等待的条件expected_conditions.此处使用
#presence_of_element_located,代表节点出现的意思,注意传入1个元祖参数来定位
email_input = wait.until(EC.presence_of_element_located((By.NAME,'email'))) #传一个tuple
print(email_input.get_attribute('data-type'))
email_input.send_keys(user)
pwd_input = browser.find_element_by_name('password')
pwd_input.send_keys(pwd)
login_em = browser.find_element_by_id('dologin')#找到登陆按钮
login_em.click()#点击登陆按钮
#browser.implicitly_wait(10) #隐式等待
#print(browser.page_source)
起初未考虑switch_to_frame时报错如下,参考https://blog.youkuaiyun.com/weixin_42937385/article/details/88150379知道了先进入子frame中。
二、学习任务b: 抓取西刺代理,并构建自己的代理池
查找网络资料,说代理分类如下
- 透明代理
- 匿名代理
- 高匿代理
透明代理在HTTP头里设置了你的真实IP,服务器可以通过HTTP头知晓你真实的IP。
匿名代理虽然隐藏了你的真实IP,但服务器还是知道你使用了代理。
高匿代理不仅隐藏了你的真实IP,而且让服务器无法发现你在使用代理,这是我们自建代理池的最佳的选择,我们下一步自建代理池的步骤中用到的也是高匿代理。
HTTP 代理,只代理 HTTP 网站,对于 HTTPS 的网站不起作用,也就是说,用的是本机 IP,反之亦然。所以本次任务建立的代理池计划用结构化数据,方便验证代理类型
https://www.xicidaili.com/nn/2,不过此次学习只是体验一把,仅抓取第一页数据。
思路和目标:
- 使用requests拿到html页面
- 使用我用起来最习惯的BeautifulSoup解析html数据
- 输出结构化数据,这里尝试使用了collecitons模块中的OrderedDict。
- 尝试使用多线程,减少爬取时间
西刺站点网页分析:
- 西刺站点信息非常规整,高匿代理页面地址如下https://www.xicidaili.com/nn,url后面加数字可以翻页
- 每页100条数据,加上1个标题。
- 每条代理所有信息包裹在在1个tr标签里。该条代理10项分类信息包裹在10个td标签里。
import requests
from bs4 import BeautifulSoup
from collections import OrderedDict
from threading import Thread
from datetime import datetime
start_time = datetime.now()
def get_xici_proxy(url,headers):
response = requests.get(url, headers=headers).content
res = response.decode('utf-8')
soup = BeautifulSoup(res, 'lxml')
tag_tr_all = soup.find_all('tr')
# ['国家', 'IP地址', '端口', '服务器地址', '是否匿名', '类型', '速度', '连接时间', '存活时间', '验证时间']
info_names = tag_tr_all[0].get_text().strip().split('\n')
# global proxy_list
t_list = []
for tag_tr in tag_tr_all[1:]: #从第1行开始遍历,应该遍历100次。
tag_td = tag_tr.find_all('td')#
try:
country = tag_td[0].img['alt'] #td字标签img里的属性值,为国家缩写,但有的没有需处理异常
except TypeError:#
country = 'None'
try:
ip_info_list = [td.get_text(strip=True) for td in tag_td[1:]] #遍历1条代理的其它信息
ip_info_list.insert(0,country)
ip_info_dict = OrderedDict(zip(info_names,ip_info_list))
t = Thread(target =check_proxy,args=(ip_info_dict,))
t_list.append(t)
except Exception as e:
print("西陆站点登录错误:",e)
for i in range(len(tag_tr_all[1:])):
t_list[i].start()
for i in range(len(tag_tr_all[1:])):
t_list[i].join()
def check_proxy(info):
# 居然要小写才行?今后抽空查资料看看是否这么一回事儿。
proxy = {info['类型'].lower():r"{}://{}:{}".format(info['类型'].lower(),info['IP地址'],info['端口']),}
try:
response1 = requests.get(r"http://httpbin.org/get",proxies=proxy,timeout=10)
print(response1.status_code)
if response1.status_code==200:
info['proxy'] = proxy
proxy_list.append(info)
except Exception as e:
pass#
if __name__ == "__main__":
url = r"https://www.xicidaili.com/nn"
headers = {
'User-Agent': "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
}
proxy_list = [] #所有有效代理都存到一个list中
get_xici_proxy(url,headers)
print("有效代理数量:",len(proxy_list))
print("第二个代理地址:",proxy_list[1].get('proxy'))
print("第二个代理地址是否匿名:",proxy_list[1].get('是否匿名'))
print("第二个代理地址类型:",proxy_list[1].get('类型'))
print("检测的第二个代理地址存活时间:",proxy_list[1].get('存活时间'))
print("_"*20)
use_time = datetime.now()- start_time
print("程序运行共计耗时:{}秒".format(use_time.seconds))
拿到proxy_list这个机构化数据,可以pickle到本地或到数据库,或者干脆存放在缓存里,在此基础上甚至可以构建一个自动运行的、动态的代理地址池。
print一下部分结果,是我想要的效果。

df2[0].columns = col_names
df2[0]
效果如下,感觉真是太太好用了,解析网页只需一行代码啊!!!以后做爬虫项目,表格类的事情就靠pandas了。