1. 程式人生 > 實用技巧 >爬取免費代理IP並測試

爬取免費代理IP並測試

爬取免費代理IP並測試




寫在開頭:這次總共爬了三個代理ip的網站,前兩個網站經過測試,ip並不能訪問我真正想爬的網站


一. 三一代理


這是我爬的第一個代理ip網站,爬的都是https的ip
1. 網頁結構

首先,想要爬一個網站,肯定要先了解一下網站html的結構

這是網頁的圖片,通過頁面,我們大概知道他是一個table的形式來顯示資料的,然後我們通過F12的審查元素來看看他的具體html程式碼。

通過檢視html程式碼,我們可以發現,整個table有一個屬性,他的類名叫做table table-striped,那麼我們之後就可以通過選取這個類名來準確獲取到這個表的資料了。再來看第一個<tr>標籤,這個<tr>標籤顯示的是表頭,也就是表中每個欄位的名字,所以我們在之後爬取的時候需要跳過第一個<tr>,爬取之後的tr標籤。接著我們再仔細觀察,一個<tr>裡面有好多個<td>標籤,其中第二個<td>存放的是ip,第三個<td>存放的是埠號,那麼我們可以知道,根據table的規則,每一行的第二個和第三個都是ip和埠號,所以我們就知道該怎麼爬取這幾個資料了。接下來,我們一起看看具體怎麼敲程式碼來爬取資料。

2. 匯入庫
from lxml import etree
import requests
from bs4 import BeautifulSoup
import os
import re
import time
import random
3. 定義的一些全域性變數

我不想定義在函式內,而且又是不會變的東西,所以就寫在函式外面,寫成全域性變數,url是代理ip的網站網址,basepath是當前程式執行的路徑,user-agent是請求頭中的引數,訪問網站時,網站會根據請求頭中的引數來識別訪問者是誰(最簡單的反爬措施,因為網站還可以通過cookie和ip等東西來判斷來訪者)

url='http://31f.cn/https-proxy/'             #目標網站
basePath = os.getcwd()                       #當前程式所在的路徑
userAgentList = [                            #user-agent列表
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
    "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3823.400 QQBrowser/10.7.4307.400",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4315.4 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",
    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
    "Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)",
]
timeout = 10                                 #連線超時時間
4. 獲取網頁html程式碼部分

這裡最好是要做try catch處理的,但是因為爬的東西少,而且簡單,也就沒去做異常處理了
在請求頭中選擇不同的user-agent可以一定程度上避免被網站監測到是爬蟲,其效果較差

def get_one_page(url): 
    global timeout
    time.sleep(5)                                             #睡眠1秒,避免頻繁範圍
    headers={                                                 #在請求頭中加入user-agent引數,通過random庫,
        'User-Agent':random.choice(userAgentList),            #隨機選取上面user-agent列表中的一條user-agent
    }
    response=requests.get(                                    #發起請求
        url,                                                  #目標網站
        headers=headers,                                      #請求頭
        timeout=timeout,                                      #超時時間
        verify=False,                                         #不檢測ssl證書
    )
    if response.status_code==200:                             #響應狀態碼為200的情況,表示訪問成功
        response.close()                                      #按網上的方法來的,避免連線太多
        return response.text                                  #返回目標網站的html程式碼
    return None
5. 解析html部分

這部分主要就是把獲取的html解析成特定的格式,然後從中獲取自己所需的標籤和資料

def parse_one_page(html):                                     #解析html部分
    ipList = {}
    okList = {}
    soup=BeautifulSoup(html,'lxml')                           #用beautifulsoup進行解析
    table = soup.find_all(class_="table table-striped")[0]    #選取html程式碼中class為table table-striped的第一個標籤
#     print(table)
    trList = table.select("tr")                               #再選取其中標籤為tr的所有標籤
    for i in range(len(trList)):                              #迴圈獲取tr的標籤列表
        if (i != 0):                                          #由於第一個tr是表頭中的tr,所以我們要去掉第一個tr,所以i要不等於0
            tdList = trList[i].select("td")                   #選取當前tr標籤中的td標籤
#             print(tdList)
#             print(tdList[1].next_element)
#             print(tdList[1].next_element+":"+tdList[2].next_element)
            ip = tdList[1].next_element+":"+tdList[2].next_element   #通過分析html程式碼我們可以知道,第二個和第三個td是我們需要的ip和埠號
            aDict = {"https":ip}                              #將ip做成一個字典(其實這麼做是錯的,字典的key只能唯一,所以會覆蓋之前的ip)
            ok = checkIpIsOK(aDict)                           #測試這個ip能不能訪問之後真正想爬取的網站(請看我下一篇部落格)
            ipList.update(aDict)                              #將aDict存進ipList
            okList.update({ip:ok})                            #如果測試ip可以成功訪問的,就把ip存進okList
    return ipList,okList                                      #這個return其實沒用,因為我直接在上面進行了檢測,不需要出去再檢測
6. 檢測ip是否可用部分

其實和第四步的程式碼基本相同,只是換了個不同的url而已

def checkIpIsOK(ipList):                                     #檢測ip是否可以成功訪問的函式
    headers={
        'User-Agent':random.choice(userAgentList),
    }
    try:
        response=requests.get(
            url='https://unpkg.com/browse/[email protected]/',
            headers=headers,
            timeout=timeout,
            verify=False,
            proxies=ipList,
        )
        if response.status_code==200:                        #只要狀態碼是200就說明可以正常訪問,不需要做更多操作
            response.close()
            return True
        return False
    except BaseException:
        return False
7. 主函式

這裡我本來是想最後再一塊檢測ip是否可用的,但是後來想想,爬一個檢測一個更方便,這樣工作量小一點,所以就把檢測放到爬取中間做了。

def main():
    global url
    html=get_one_page(url)
    ipList,okList = parse_one_page(html)
    print(okList)
#     checkIpIsOK(ipList)

main()
8.最後結果

結果說明,這個網站的免費代理ip無法當做我的代理ip去爬我想爬的網站




二.齊雲代理


這是我爬的第二個網站,這個網站和上一個大體相同,不同的地方是這個網站ip量大,有做分頁處理,所以可以爬很多個頁面。
##### 1. 網頁結構 和第一個網站一樣,首先先來分析一下網頁結構 ![](https://img2020.cnblogs.com/blog/1929795/202012/1929795-20201219194107113-592556512.png) ![](https://img2020.cnblogs.com/blog/1929795/202012/1929795-20201219203350746-609624334.png) 這是網站的頁面,首先先來注意一下這個網址,當我點選第二頁後,他變成了這樣子。說明這個網站是通過在url後面追加page這個引數來顯示不同的頁面的,所以,我們之後只需要動態變化這個page的值就可以做到爬取每一頁的內容了。接下來F12審查元素看看網頁原始碼, ![](https://img2020.cnblogs.com/blog/1929795/202012/1929795-20201219194601240-594542956.png) 首先和第一個網站一樣,這都是一個table的形式,\的類名叫table table-bordered table-striped,接著注意這個\,第一個\存放的內容是表頭,所以我們還是照例需要跳過。 然後我們來看看接下來的\標籤,\還是有好幾個\,第一個\是ip,第二個\是埠號,所以同樣的方法,我們開始爬蟲。 ##### 2. 匯入庫 ```python from lxml import etree import requests from bs4 import BeautifulSoup import os import re import time import random ``` ##### 3. 定義的一些全域性變數 大體和第一個網站的程式碼相同,但是注意,這裡的url沒有page的引數,只到page=,因為後面的頁碼,需要我們動態新增,不能寫死。 ```python url='https://www.7yip.cn/free/?action=china&page=' #目標網站 basePath = os.getcwd() #當前程式所在的路徑 userAgentList = [ #user-agent列表 "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)", "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3823.400 QQBrowser/10.7.4307.400", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4315.4 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50", "Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)", ] timeout = 10 #連線超時時間 ipList = {} #這裡我把這兩個列表也直接全域性變量了 okList = {} #這裡我把這兩個列表也直接全域性變量了 ``` ##### 4. 獲取網頁html程式碼部分 這裡和第一個網站的程式碼基本相同,沒做什麼改動,就去掉了睡眠時間,ssl證書檢測和超時時間,因為對於爬取這種小小的東西來說,實在沒必要加著 ```python def get_one_page(url): global timeout # time.sleep(5) #睡眠1秒,避免頻繁範圍 headers={ #在請求頭中加入user-agent引數,通過random庫, 'User-Agent':random.choice(userAgentList), #隨機選取上面user-agent列表中的一條user-agent } response=requests.get( #發起請求 url, #目標網站 headers=headers, #請求頭 # timeout=timeout, #超時時間 # verify=False, #不檢測ssl證書 ) if response.status_code==200: #響應狀態碼為200的情況,表示訪問成功 response.close() #按網上的方法來的,避免連線太多 return response.text #返回目標網站的html程式碼 return None ``` ##### 5. 解析html部分 這裡和第一個網站的程式碼也是基本相同,我甚至震驚了,看上去也沒用什麼前端框架,頁面效果完全不同的兩個網站,其中的類名竟然驚人的相似。 ```python def parse_one_page(html): #解析html部分 global ipList,okList soup=BeautifulSoup(html,'lxml') #用beautifulsoup進行解析 table = soup.find_all(class_="table table-bordered table-striped")[0] #選取html程式碼中class為table table-bordered table-striped的第一個標籤 # print(table) trList = table.select("tr") #再選取其中標籤為tr的所有標籤 # print(trList) for i in range(len(trList)): #迴圈獲取tr的標籤列表 if (i != 0): #由於第一個tr是表頭中的tr,所以我們要去掉第一個tr,所以i要不等於0 tdList = trList[i].select("td") #選取當前tr標籤中的td標籤 # print(tdList) # print(tdList[1].next_element) # print(tdList[1].next_element+":"+tdList[2].next_element) ip = tdList[0].next_element+":"+tdList[1].next_element #通過分析html程式碼我們可以知道,第一個和第二個td是我們需要的ip和埠號 aDict = {"https":ip} #將ip做成一個字典(其實這麼做是錯的,字典的key只能唯一,所以會覆蓋之前的ip) ok = checkIpIsOK(aDict) #測試這個ip能不能訪問之後真正想爬取的網站(請看我下一篇部落格) ipList.update(aDict) #將aDict存進ipList okList.update({ip:ok}) #如果測試ip可以成功訪問的,就把ip存進okList return ipList,okList #這個return其實沒用,因為這兩個list已經是全域性變量了,外面也可以看得到 ``` ##### 6. 檢測ip是否可用部分 這裡和上面的程式碼完全一樣,因為整個程式碼我都是複製上一個網站的過來改的ヾ(@^▽^@)ノ ```python def checkIpIsOK(ipList): #檢測ip是否可以成功訪問的函式 headers={ 'User-Agent':random.choice(userAgentList), } try: response=requests.get( url='https://unpkg.com/browse/[email protected]/', headers=headers, timeout=timeout, verify=False, proxies=ipList, ) if response.status_code==200: #只要狀態碼是200就說明可以正常訪問,不需要做更多操作 response.close() return True return False except BaseException: return False ``` ##### 7. 主函式 這裡稍微和第一個網站有些區別了,通過for迴圈,動態新增url中的page引數,使得可以爬取每頁的內容。 ```python def main(): global url for i in range(10): #通過迴圈取得一個數字i html=get_one_page(url+str(i+1)) #因為迴圈是從0開始的,所以i+1,並且轉換成str型別新增在url末尾 parse_one_page(html) print(okList) # checkIpIsOK(ipList)

main()

##### 8.最後結果
結果說明,這個網站的免費代理ip還是無法當做我的代理ip去爬我想爬的網站
![](https://img2020.cnblogs.com/blog/1929795/202012/1929795-20201219200717451-1049784255.png)
</br></br></br>
### 二.齊雲代理
</br>
這是我爬的第三個網站,首先一提,這個網站的ip有很多可用的,所以這是我爬的最後一個網站
</br>
##### 1. 網頁結構
首先,還是看看網頁結構
![](https://img2020.cnblogs.com/blog/1929795/202012/1929795-20201219202557141-841460534.png)
同樣的也是table的樣子,然後我們通過審查元素看看原始碼
![](https://img2020.cnblogs.com/blog/1929795/202012/1929795-20201219202710637-1612284338.png)
大致相同的佈局,和前兩個基本沒差,注意table的類名叫fl-table,第一個\<tr\>是表頭,每一列的第一個\<td\>是ip和埠號
##### 2. 匯入庫
```python
from lxml import etree
import requests
from bs4 import BeautifulSoup
import os
import re
import time
import random
3. 定義的一些全域性變數

和上面的一樣,除了url有變化

url='http://www.xiladaili.com/https/'                          #目標網站
basePath = os.getcwd()                                         #當前程式所在的路徑
userAgentList = [                                              #user-agent列表
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
    "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3823.400 QQBrowser/10.7.4307.400",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4315.4 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",
    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
    "Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)",
]
timeout = 10                                                    #連線超時時間
ipList = {}                                                     #這裡我把這兩個列表也直接全域性變量了
okList = {}                                                     #這裡我把這兩個列表也直接全域性變量了
4. 獲取網頁html程式碼部分

和上面的一樣

def get_one_page(url): 
    global timeout
#     time.sleep(5)                                             #睡眠1秒,避免頻繁範圍
    headers={                                                   #在請求頭中加入user-agent引數,通過random庫,
        'User-Agent':random.choice(userAgentList),              #隨機選取上面user-agent列表中的一條user-agent
    }
    response=requests.get(                                      #發起請求
        url,                                                    #目標網站
        headers=headers,                                        #請求頭
#         timeout=timeout,                                      #超時時間
#         verify=False,                                         #不檢測ssl證書
    )
    if response.status_code==200:                               #響應狀態碼為200的情況,表示訪問成功
        response.close()                                        #按網上的方法來的,避免連線太多
#         print(response.text)
        return response.text                                    #返回目標網站的html程式碼
    return None
5. 解析html部分

基本沒變,稍微改了一點地方

def parse_one_page(html):                                       #解析html部分
    global ipList,okList
    soup=BeautifulSoup(html,'html5lib')                         #用beautifulsoup進行解析,這個地方稍微有點不同,lxml解析不了,需要跳過html5lib來解析
    table = soup.find_all(class_="fl-table")[0]                 #選取html程式碼中class為fl-table的第一個標籤
#     print(table)
    trList = table.select("tr")                                 #再選取其中標籤為tr的所有標籤
#     print(trList)
    for i in range(len(trList)):                                #迴圈獲取tr的標籤列表
        if (i != 0):                                            #由於第一個tr是表頭中的tr,所以我們要去掉第一個tr,所以i要不等於0
            tdList = trList[i].select("td")                     #選取當前tr標籤中的td標籤
#             print(tdList)
#             print(tdList[1].next_element)
#             print(tdList[1].next_element+":"+tdList[2].next_element)
#             ip = tdList[0].next_element+":"+tdList[1].next_element
            ip = tdList[0].next_element                         #通過分析html程式碼我們可以知道,第一個td是我們需要的ip和埠號
#             print(ip)
            aDict = {"https":ip}                                #將ip做成一個字典(其實這麼做是錯的,字典的key只能唯一,所以會覆蓋之前的ip)
            ok = checkIpIsOK(aDict)                             #測試這個ip能不能訪問之後真正想爬取的網站(請看我下一篇部落格)
            ipList.update(aDict)                                #將aDict存進ipList
            okList.update({ip:ok})                              #如果測試ip可以成功訪問的,就把ip存進okList
    return ipList,okList                                        #這個return其實沒用,因為這兩個list已經是全域性變量了,外面也可以看得到
6. 檢測ip是否可用部分

沒改動

def checkIpIsOK(ipList):                                    #檢測ip是否可以成功訪問的函式
    headers={
        'User-Agent':random.choice(userAgentList),
    }
    try:
        print(ipList)
        response=requests.get(
            url='https://unpkg.com/browse/[email protected]/',
            headers=headers,
            timeout=timeout,
            verify=False,
            proxies=ipList,
        )
        if response.status_code==200:                        #只要狀態碼是200就說明可以正常訪問,不需要做更多操作
            print("ok")
            response.close()
            return True
        return False
    except BaseException:
        return False
7. 主函式

這裡稍微和第一個網站有些區別了,通過for迴圈,動態新增url中的page引數,使得可以爬取每頁的內容。

def main():
    global url
    for i in range(1):                                       #不需要迴圈,但是懶得改程式碼了,所以就迴圈改成1,相當於沒有迴圈
        html=get_one_page(url)
        parse_one_page(html)
#     print(okList)
#     checkIpIsOK(ipList)

main()
8.最後結果

終於成功了,有很多可用的ip