Python建立ip代理池(多線程)

轉載自公眾號:JAVAandPythonJun

說在前面的話

Hello,我是JAP君,相信經常使用爬蟲的朋友對代理ip應該比較熟悉,代理ip就是可以模擬一個ip地址去訪問某個網站。我們有時候需要爬取某個網站的大量信息時,可能由于我們爬的次數(shù)太多導致我們的ip被對方的服務器暫時屏蔽(也就是所謂的防爬蟲防洪水的一種措施),這個時候就需要我們的代理ip出場了,今天我?guī)Т蠹襾砼廊∥鞔檀砩厦婷赓M提供的代理ip并且我們來檢測它的有效性來打造我們自己的代理ip池,廢話不多說,咱們動工!

2思路分析(寫爬蟲前大家都必須要分析一下)

image
image

沒錯上圖就是我們的西刺代理網站啦,今天我們就是來拿它的數(shù)據(jù),老司機一看這個界面就會自動右擊鼠標->查看源代碼,我們也來看看:

image

我們會發(fā)現(xiàn)數(shù)據(jù)都在<tr>里面,并且<tr>里面有很多的<td>,每一個<td>都包含了我們所需要的數(shù)據(jù)。

看過我以前一些爬蟲文章的朋友估計一下就知道該怎么下手了,但是不急我們還是來分析一下,畢竟這次數(shù)據(jù)量有點大,而且還得校驗代理ip的有效性。

image

給大家畫了張圖,其實思路也很簡單,也就不多闡述了。

3獲取所有的代理ip以及相關信息并保存至文件txt中

我們就按照我們的思路來,在這里我們需要用到的幾個庫,給大家寫出來:

from bs4 import BeautifulSoup
import requests
from urllib import request,error
import threading

導入庫后,我們首先獲得代理ip,我們來定義一個方法:(每一句的解釋我都寫在注釋里了)

def getProxy(url):
   # 打開我們創(chuàng)建的txt文件
   proxyFile = open('proxy.txt', 'a')
   # 設置UA標識
   headers = {
       'User-Agent': 'Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit '
                     '/ 537.36(KHTML, likeGecko) Chrome / 63.0.3239.132Safari / 537.36'
   }
   # page是我們需要獲取多少頁的ip,這里我們獲取到第9頁
   for page in range(1, 10):
       # 通過觀察URL,我們發(fā)現(xiàn)原網址+頁碼就是我們需要的網址了,這里的page需要轉換成str類型
       urls = url+str(page)
       # 通過requests來獲取網頁源碼
       rsp = requests.get(urls, headers=headers)
       html = rsp.text
       # 通過BeautifulSoup,來解析html頁面
       soup = BeautifulSoup(html)
       # 通過分析我們發(fā)現(xiàn)數(shù)據(jù)在 id為ip_list的table標簽中的tr標簽中
       trs = soup.find('table', id='ip_list').find_all('tr') # 這里獲得的是一個list列表
       # 我們循環(huán)這個列表
       for item in trs[1:]:
           # 并至少出每個tr中的所有td標簽
           tds = item.find_all('td')
           # 我們會發(fā)現(xiàn)有些img標簽里面是空的,所以這里我們需要加一個判斷
           if tds[0].find('img') is None:
               nation = '未知'
               locate = '未知'
           else:
               nation = tds[0].find('img')['alt'].strip()
               locate = tds[3].text.strip()
           # 通過td列表里面的數(shù)據(jù),我們分別把它們提取出來
           ip = tds[1].text.strip()
           port = tds[2].text.strip()
           anony = tds[4].text.strip()
           protocol = tds[5].text.strip()
           speed = tds[6].find('div')['title'].strip()
           time = tds[8].text.strip()
           # 將獲取到的數(shù)據(jù)按照規(guī)定格式寫入txt文本中,這樣方便我們獲取
           proxyFile.write('%s|%s|%s|%s|%s|%s|%s|%s\n' % (nation, ip, port, locate, anony, protocol, speed, time))

上面的代碼就是我們抓取西刺代理上的所有ip并將它們寫入txt中,每一句的解釋我都寫在注釋里面了,這里也就不多說了。

4校驗代理ip的可用性

這里我是通過代理ip去訪問百度所返回的狀態(tài)碼來辨別這個代理ip到底有沒有用的。

def verifyProxy(ip):
   '''
   驗證代理的有效性
   '''
   requestHeader = {
       'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36"
   }
   url = "http://www.baidu.com"
   # 填寫代理地址
   proxy = {'http': ip}
   # 創(chuàng)建proxyHandler
   proxy_handler = request.ProxyHandler(proxy)
   # 創(chuàng)建opener
   proxy_opener = request.build_opener(proxy_handler)
   # 安裝opener
   request.install_opener(proxy_opener)

   try:
       req = request.Request(url, headers=requestHeader)
       rsq = request.urlopen(req, timeout=5.0)
       code = rsq.getcode()
       return code
   except error.URLError as e:
       return e

我們在這個方法中會得到一個狀態(tài)碼的返回,如果返回碼是200,那么這個代理ip就是可用的。

image
def verifyProxyList():
   
   verifiedFile = open('verified.txt', 'a')

   while True:
       lock.acquire()
       ll = inFile.readline().strip()
       lock.release()
       if len(ll) == 0 : break
       line = ll.strip().split('|')
       ip = line[1]
       port = line[2]
       realip = ip+':'+port
       code = verifyProxy(realip)
       if code == 200:
           lock.acquire()
           print("---Success:" + ip + ":" + port)
           verifiedFile.write(ll + "\n")
           lock.release()
       else:
           print("---Failure:" + ip + ":" + port)

我們寫完校驗方法后,我們就從我們事先爬取到的所有代理ip的txt文件中獲取到ip和端口(ip地址:端口),我們通過判斷返回值是否為200來進行寫入到有效的txt文件中。

5調用函數(shù)

萬事俱備只欠調用!

if __name__ == '__main__':
   tmp = open('proxy.txt', 'w')
   tmp.write("")
   tmp.close()
   tmp1 = open('verified.txt', 'w')
   tmp1.write("")
   tmp1.close()
   getProxy("http://www.xicidaili.com/nn/")
   getProxy("http://www.xicidaili.com/nt/")
   getProxy("http://www.xicidaili.com/wn/")
   getProxy("http://www.xicidaili.com/wt/")

   all_thread = []
   # 30個線程
   for i in range(30):
       t = threading.Thread(target=verifyProxyList)
       all_thread.append(t)
       t.start()

   for t in all_thread:
       t.join()

   inFile.close()
   verifiedtxt.close()

因為西刺代理提供了四種代理ip,所以分別有四個網址。這里我們也采用了線程的方法,主要是為了防止出現(xiàn)線程互相爭奪導致我們的數(shù)據(jù)不精確,在上面幾個方法中我們也通過了同步鎖來對其進行線程安全的保證。

6結尾

其實總體來說這個爬蟲不是特別的難,主要的難點在于數(shù)據(jù)量可能有點多,很多人可能不會考慮到線程安全的問題,導致數(shù)據(jù)獲取的不精確。

全部代碼:

from bs4 import BeautifulSoup
import requests
from urllib import request,error
import threading


inFile = open('proxy.txt')
verifiedtxt = open('verified.txt')
lock = threading.Lock()
def getProxy(url):
    # 打開我們創(chuàng)建的txt文件
    proxyFile = open('proxy.txt', 'a')
    # 設置UA標識
    headers = {
        'User-Agent': 'Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit '
                      '/ 537.36(KHTML, likeGecko) Chrome / 63.0.3239.132Safari / 537.36'
    }
    # page是我們需要獲取多少頁的ip,這里我們獲取到第9頁
    for page in range(1, 10):
        # 通過觀察URL,我們發(fā)現(xiàn)原網址+頁碼就是我們需要的網址了,這里的page需要轉換成str類型
        urls = url+str(page)
        # 通過requests來獲取網頁源碼
        rsp = requests.get(urls, headers=headers)
        html = rsp.text
        # 通過BeautifulSoup,來解析html頁面
        soup = BeautifulSoup(html)
        # 通過分析我們發(fā)現(xiàn)數(shù)據(jù)在 id為ip_list的table標簽中的tr標簽中
        trs = soup.find('table', id='ip_list').find_all('tr') # 這里獲得的是一個list列表
        # 我們循環(huán)這個列表
        for item in trs[1:]:
            # 并至少出每個tr中的所有td標簽
            tds = item.find_all('td')
            # 我們會發(fā)現(xiàn)有些img標簽里面是空的,所以這里我們需要加一個判斷
            if tds[0].find('img') is None:
                nation = '未知'
                locate = '未知'
            else:
                nation = tds[0].find('img')['alt'].strip()
                locate = tds[3].text.strip()
            # 通過td列表里面的數(shù)據(jù),我們分別把它們提取出來
            ip = tds[1].text.strip()
            port = tds[2].text.strip()
            anony = tds[4].text.strip()
            protocol = tds[5].text.strip()
            speed = tds[6].find('div')['title'].strip()
            time = tds[8].text.strip()
            # 將獲取到的數(shù)據(jù)按照規(guī)定格式寫入txt文本中,這樣方便我們獲取
            proxyFile.write('%s|%s|%s|%s|%s|%s|%s|%s\n' % (nation, ip, port, locate, anony, protocol, speed, time))


def verifyProxyList():
    
    verifiedFile = open('verified.txt', 'a')

    while True:
        lock.acquire()
        ll = inFile.readline().strip()
        lock.release()
        if len(ll) == 0 : break
        line = ll.strip().split('|')
        ip = line[1]
        port = line[2]
        realip = ip+':'+port
        code = verifyProxy(realip)
        if code == 200:
            lock.acquire()
            print("---Success:" + ip + ":" + port)
            verifiedFile.write(ll + "\n")
            lock.release()
        else:
            print("---Failure:" + ip + ":" + port)




def verifyProxy(ip):
    '''
    驗證代理的有效性
    '''
    requestHeader = {
        'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36"
    }
    url = "http://www.baidu.com"
    # 填寫代理地址
    proxy = {'http': ip}
    # 創(chuàng)建proxyHandler
    proxy_handler = request.ProxyHandler(proxy)
    # 創(chuàng)建opener
    proxy_opener = request.build_opener(proxy_handler)
    # 安裝opener
    request.install_opener(proxy_opener)

    try:
        req = request.Request(url, headers=requestHeader)
        rsq = request.urlopen(req, timeout=5.0)
        code = rsq.getcode()
        return code
    except error.URLError as e:
        return e

if __name__ == '__main__':
    tmp = open('proxy.txt', 'w')
    tmp.write("")
    tmp.close()
    tmp1 = open('verified.txt', 'w')
    tmp1.write("")
    tmp1.close()
    getProxy("http://www.xicidaili.com/nn/")
    getProxy("http://www.xicidaili.com/nt/")
    getProxy("http://www.xicidaili.com/wn/")
    getProxy("http://www.xicidaili.com/wt/")

    all_thread = []
    for i in range(30):
        t = threading.Thread(target=verifyProxyList)
        all_thread.append(t)
        t.start()

    for t in all_thread:
        t.join()

    inFile.close()
    verifiedtxt.close()
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容