1. 程式人生 > >爬蟲I號 :獲取免費代理伺服器&進行代理驗證

爬蟲I號 :獲取免費代理伺服器&進行代理驗證

閒來無聊,正兒八經寫的個人第一Python小程式

                ------爬蟲I號:獲取免費代理伺服器&自動驗證

  • 需求:

           不要問我為什麼要用代理,有需求的自然明白。

  • 知識點:

          1.list的使用

          2.file操作的使用

          3.類的使用

          4.requests 模組的使用,為了獲取西刺網站的頁面,也用於驗證代理IP是否有效;不喜歡用urllib

          5.正則表示式的使用,為了爬網頁,也可以考慮用Beautifulsoup,看需求了

          6.try, with等異常處理語句的使用

  • 設計流程:

          設計思想很簡單,細分以下幾個步驟:

                  1.初始化類,配置Proxy 資源網站URL,用於驗證Proxy IP的URL,存取Proxy IP的檔案

                  2.獲取Proxy資源網站內容

                  3.通過正則表示式爬 IP和Port資源,蒐集成Proxy_all_list

                  4.驗證Proxy_all_list中的每一個IP,並記錄有效IP

話不多說,直接上Code,有詳細註解。

#coding=utf-8
#<<<Web crawler I>>> : Get & Verify Proxy , written by HuangYu 20180814

import re           #正則表示式庫,用來匹配網頁元素
import socket       #用於設定網路連線的相關屬性
import sys          
import requests     #用於進行HTTP的相關處理,urllib庫用起來還是比較煩的,requests用起來so easy
import logging      #log相關功能,不能總是用print那麼low

class ProxyProber:
            
    def __init__(self):  #類的初始化函式,在類中的函式都有個self引數,其實可以理解為這個類的物件
        
        self.file_proxy_all_list = "proxy_all.txt"                   #儲存 免費代理伺服器網站 爬下來的所有代理IP
        self.file_proxy_valid_list = "proxy_valid.txt"               #儲存 通過驗證可用的 代理IP
        self.proxy_resource = "http://www.xicidaili.com/wn/"         #用於爬取代理資訊的網站
        self.verify_url = "http://www.baidu.com/"                    #用於驗證Proxy IP的網站

        #要為http報文分配header欄位,否則很多頁面無法獲取
        self.http_headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0',
        'Accept-Encoding': 'gzip, deflate'
        }
        #配置log資訊儲存的位置
        logging.basicConfig(filename='./proxy_debug.log', filemode="w", level=logging.DEBUG)
        #3秒內沒有開啟web頁面,就放棄等待,防止死等,不管哪種語言,都要防範網路阻塞造成程式響應遲滯,CPU經常因此被冤枉
        socket.setdefaulttimeout(3)
        
    def getWebInfoByRe(self, context): #用於通過正則表示式取頁面中的關鍵資訊,context是頁面內容
        ip_port_list = [] 
        get_ip_re = re.compile("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") #取頁面中所有格式為“數字.數字.數字.數字”的資料存入IP列表
        ip_list = get_ip_re.findall(str(context))                    
        get_port_raw_re = re.compile("<td>\d{2,5}</td>")             #取頁面中所有的格式為“<td>數字</td>”的資料存入Port草稿列表
        port_list_raw = get_port_raw_re.findall(str(context))
        get_port_re = re.compile("\d{5}|\d{4}|\d{2}")                #取上一批資料中所有的 “數字” 存入Port列表
        port_list = get_port_re.findall(str(port_list_raw))
		
        if ip_list is None:  
            return None 
        if port_list is None:  
            return None
        if len(ip_list)!=len(port_list):                             #理論上IP和Port應該成對出現,沒有再做太多的容錯處理
            return None
		
        for index in range(len(ip_list)):		             #將IP和Port列表中的資料一一匹配成“IP:Port”的格式存入list
            ip_port_list.append(str(ip_list[index]) + ":" + str(port_list[index]))
            
        return ip_port_list
      
    def getProxyResource(self,url): #獲取代理伺服器網站資訊,並儲存

        if len(url)==0:  
            print("Url is null!")
            return

        requests.adapters.DEFAULT_RETRIES = 5
        proxy_resource_request = requests.session()
        proxy_resource_request.keep_alive = False
        #獲取url內容
        try:
            proxy_resource_result =proxy_resource_request.get(url, headers=self.http_headers)
        except:
            print("proxy_resource can't get!!!")
            return
        #頁面內容存入log檔案,爬頁面的時候,都要獲取頁面原始碼分析其中的關鍵元素;當然,你也可以使用瀏覽器的debug元件分析
        logging.debug(proxy_resource_result.content)

        #開始提取頁面中的IP和Port列表
        proxy_list = self.getWebInfoByRe(proxy_resource_result.content)
        
        #統計list元素個數
        print(len(proxy_list))  
          
        if len(proxy_list)==0:  
            print("Get Proxy fail!")  
            return
        
        #將list中所有資訊寫入proxy_all.txt
        fd_proxy_all = open(self.file_proxy_all_list, 'w')

        #with as 語法的使用,可以省去close檔案的過程
        with open(self.file_proxy_all_list, 'w') as fd_proxy_all:
            for ip_port in proxy_list:  
                fd_proxy_all.write(str(ip_port) + "\n")


    def verifyProxy(self): #從proxy_all.txt獲取所有Proxy IP進行驗證,將有效的IP存入proxy_valid.txt
        index = 0
        requests.adapters.DEFAULT_RETRIES = 5
        test_proxy = requests.session()
        test_proxy.keep_alive = False
        
        #將proxy_all.txt中所有資訊讀到ip_port_list中,
        with open(self.file_proxy_all_list, 'r') as fd_proxy_all:
            ip_port_list = fd_proxy_all.readlines()#讀取全部內容
            
        #建立一個新的proxy_valid.txt    
        try:
            fd_proxy_valid = open(self.file_proxy_valid_list,'w')
        except:
            print ("proxy_valid.txt open is fail!")
            return
        finally:
            fd_proxy_valid.close()
        
        for ip_port in ip_port_list:
            proxy_url = {'http':'http://' + ip_port.strip('\n')}       #request.get資訊中需要填寫proxies欄位,欄位的format={'http':'http://ip:port'}
                                                                       #因為讀回的資訊每一行都有"\n",所以需要用.strip過濾掉"\n"

            index+=1
            print(str(index))
            
            try:
                #通過request.get獲取驗證頁面,timeout用於防止 傻等,畢竟要驗證一堆IP
                test_page =test_proxy.get(self.verify_url, headers=self.http_headers, proxies=proxy_url, timeout=(2,3))
            except: #如果獲取頁面異常,進入這兒,再處理下一個IP
                print("Invaild Proxy : " + ip_port.strip('\n'))
                continue
            #獲取正常的頁面返回碼一般都是200,不是的話繼續處理下一個IP
            if test_page.status_code!=200:
                print("Invaild Proxy : " + ip_port.strip('\n'))
                continue
            
            #能用的IP存入proxy_valid.txt
            print("*********Vaild Proxy : " + ip_port.strip('\n'))
            with open(self.file_proxy_valid_list, 'a') as fd_proxy_valid:
                fd_proxy_valid.write(ip_port.strip('\n') + " "+ str(test_page.elapsed.total_seconds()) + "\n")

if __name__ == "__main__":  
    prober_handler = ProxyProber() 
    #prober_handler.getProxyResource(sys.argv[1])
    #prober_handler.getProxyResource("http://www.xicidaili.com/wn/")
    prober_handler.getProxyResource(prober_handler.proxy_resource)     #物件名=self,看到這就可以理解類裡的self是什麼了。
    prober_handler.verifyProxy()