之前提到過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中測試如下。