之前提到过urllib和requests的利用代理ip的访问方式 。
详见:
https://blog.csdn.net/zhouchen1998/article/details/81318300
https://blog.csdn.net/zhouchen1998/article/details/81479092
但是为什么我们要使用代理ip?
答:因为利用爬虫这样的网络机器人去毫无代价的爬取网站信息不仅不道德还会给对方的服务器带来巨大负担,尽管存在着“爬虫道德”不过这也是有素质的人的自我遵守,没有什么约束力。对此网站的反爬虫策略一直没有停止过,其中一个手段就是判断你的网页操作是不是人,如果是多次频繁爬取的机器人那么属于你机器的唯一身份ip地址就会被对方封禁,你将不能访问该网站。
而针对这种措施,其中比较行之有效的方法就是我不使用自己的ip直接访问,而是使用一个虚假的代理身份去访问,一旦被封我只需要换个ip就好,不会干扰我的正常使用。
提供代理服务器获取的常用网站地址为:
这里很多短时间的免费的,对于玩玩爬虫的可以使用,如果你是专业的爬虫工程师那么建议你购买相关的代理服务。
前面我们已经介绍了两种常用的访问模块的代理使用方法,但是每次使用都要到网站中去找到一个合适的,这很不方便,看了一些博客决定建立一个模块作为代理ip的自动获取-代理ip池。
只要在需要的时候导入这个模块调用get方法就会得到一个可用的ip代理地址。
这里的代理ip池是获取的goubanjia上的最新20个代理ip足够爬虫爱好者使用,专业爬虫工程师可以购买服务,爬取更多内容。
经过元素的审查分析,可以通过元素定位和拼接得到20个ip地址。
但是有三个难点:
1:观察源代码出现这样的前后一样数值但是属性为不显示的干扰性,在获得源码并定位标签的基础上利用正则表达式替换掉了这样的p标签为空字符。
<p style="display: none;">5</p>
2: 还有一个难点是如果使用的urllib或者是requests模块那么最后的端口号是没有js加载前的,是不准确的,这里笔者未选择进行js代码研究,而是使用selenium直接获得js加载后的源码。
3: 即使剔除了干扰项,ip地址还是分立存放的,这里使用xpath的string方法获得所有的文本合并值。
import time
from bs4 import BeautifulSoup
from lxml import etree
from selenium import webdriver
import re
# 获得一组可能可用的代理ip地址
def getproxy():
# 目标地址
target_url = "http://www.goubanjia.com/"
# 使用谷歌浏览器
driver = webdriver.Chrome(r'C:\Users\16957\AppData\Local\Google\Chrome\Application\chromedriver.exe')
# 等待js加载
time.sleep(1)
# 访问地址
driver.get(target_url)
# 得到html文件
target_html = driver.page_source
# 建立bs对象
bs = BeautifulSoup(target_html, 'html.parser')
# 找到了20个存放地址的td标签
rst_etree = bs.find_all(attrs={'class': 'ip'})
index = 0
addr_list = []
# 遍历每一个td
while index < len(rst_etree):
rst_etree[index] = str(rst_etree[index])
# 用l存放所有网页分析干扰项的p标签
list_p = re.compile(r'<p.*?>[^<]*?</p>').findall(rst_etree[index])
# 将所有p标签替换为空字符
for item in list_p:
rst_etree[index] = rst_etree[index].replace(item, "")
# 通过etree里的xpath中的string方法获得ip地址
dom = etree.HTML(rst_etree[index])
ip_addr = ''
ip_addr += dom.xpath("string(.)")
addr_list.append(ip_addr)
index += 1
# 得到最新的代理ip列表
return addr_list
def check_ip(ip_list=[]):
# 使用request验证ip可用性
import requests
for item in ip_list:
proxies = {
"http": item,
"https": item
}
# 如果连接成功,且返回来内容认为ip可用,返回该ip退出循环
try:
rsp = requests.get("http://www.baidu.com", proxies=proxies)
if rsp.text is not None:
return item
break
except Exception:
pass
# 如果20个遍历完没找到可用的ip,返回none
return None
# 得到一个可用的ip地址
# 这个函数在其他地方导入该模块并且执行该函数就会返回一个可用的ip地址
def get_one_proxy_ip():
ip_list = getproxy()
if check_ip(ip_list) is not None:
return check_ip(ip_list)
else:
return None
if __name__ == '__main__':
print(get_one_proxy_ip())
在main中测试如下。