從零開始寫Python爬蟲 --- 2.4 爬蟲實踐:代理的爬取和驗證

爬網站的時候,由於各種原因,ip被鎖了,這個時候我們就需要通過代理來突破封鎖。網上有很多代理網站,付費和免費的都有,這次我們就來寫一個scrapy爬蟲,爬一些免費的代理下來用。

目標分析:

本次爬取了代理網站:

  • 大象代理:HTTP免費HTTP代理IP_HTTP
  • 快代理: 快代理 - 高速http代理ip每天更新

目標很簡單,從網上爬下ip地址和埠,保存在本地文件中

數據篩選:

相信寫了這麼多個demo,大家對於從html文件中定位元素位置都不陌生了吧?

我這裡就不寫具體是怎麼抓的了,大家可以用自己的喜歡的方法,

無論是Xpath還是CSS選賊器,或者是我們原來用的最順手的bs4

如果還是無從下手,可以回頭看看我bs4爬蟲的教程,看看我是如何做的

其實最重要的就是兩點:

  • 掌握選擇器語法
  • 熟練使用chrome開發工具

要是還是一點頭緒都沒有,可以之間看我下面實現的代碼。

項目的創建:

這一部分很簡單,就是套路東西,我也不詳細說啦,

跟著代碼來就行:

# 創建項目n scrapy startproject proxyn # c進入項目文件夾n cd proxyn # 創建xici代理爬蟲n scrapy genspider dxdlspider xicidaili.comn # 創建快代理爬蟲n scray genspider kdlspider kuaidaili.comn n # 看看目錄長啥樣n.n├── proxyn│ ├── __init__.pyn│ ├── __pycache__n│ │ ├── __init__.cpython-36.pycn│ │ ├── items.cpython-36.pycn│ │ ├── pipelines.cpython-36.pycn│ │ └── settings.cpython-36.pycn│ ├── items.pyn│ ├── middlewares.pyn│ ├── pipelines.pyn│ ├── settings.pyn│ └── spidersn│ ├── __init__.pyn│ ├── __pycache__n│ │ ├── __init__.cpython-36.pycn│ │ ├── dxdlspider.cpython-36.pycn│ │ └── kdlspider.cpython-36.pycn│ ├── dxdlspider.pyn│ └── kdlspider.pyn└── scrapy.cfgnn4 directories, 16 filesn

items的編寫:

由於我們只需要代理的埠和ip,網頁上其他花里胡哨的東西都不要,

所以items編寫起來異常的簡單:

import scrapynclass ProxyItem(scrapy.Item):n # define the fields for your item here like:n # name = scrapy.Field()n n #這個爬蟲十分簡單,我們要ip+埠,所以一個欄位就夠用了!n addr = scrapy.Field()n

Spider的編寫:

我又要來嘮叨了,這個部分還是我們scrapy框架中的核心部分!

雖然在這個例子里非常的簡單:

編寫大象代理的Spider:

在編寫這個Spider的時候,我吃驚的發現,該站張居然提供了代理的api

api:api.xicidaili.com/free2

這也就意味著,我們不用辛苦的寫代碼篩選數據了,

但是我們已經把爬蟲建立了,總不能刪了吧?那多難受!

這個簡單,我們把Response.text的內容傳給item

好! 就這樣做:

import scrapynfrom proxy.items import ProxyItemnnclass DxdlspiderSpider(scrapy.Spider):n name = "dxdlspider"n allowed_domains = ["xicidaili.com"]n start_urls = [http://api.xicidaili.com/free2016.txt]nn def parse(self, response):n item = ProxyItem()n #因為直接調用網站的api,本身get下來的就是一個text文本,n #我們直接把文本傳給item再交給pipeline處理就行n item[addr] = response.textn return itemn n

編寫快代理的Spider:

這個網站就沒有上一個那麼好了,

我們老老實實自己爬吧:

import scrapynfrom proxy.items import ProxyItemnnnclass KdlspiderSpider(scrapy.Spider):n name = "kdlspider"n allowed_domains = ["kuaidaili.com"]n start_urls = []nn # 通過簡單的循環,來生成爬取頁面的列表n # 這裡我們爬1~5頁n for i in range(1, 6):n start_urls.append(http://www.kuaidaili.com/free/inha/ + str(i) + /)nn def parse(self, response):n # 我們先實例化一個itemn item = ProxyItem()nn # 通過Xpath找到每條代理的內容n mian = response.xpath(n //table[@class="table table-bordered table-striped"]/tbody/tr)nn for li in mian:n #找到ip地址n ip = li.xpath(td/text()).extract()[0]n #找到埠:n port =li.xpath(td/text()).extract()[1]n #將兩者連接,並返回給item處理n item[addr] = ip+:+portn yield itemn

PIPELINE的編寫:

最核心和最難的爬虫部分寫完了,剩下的就是收尾工作,

我們來寫個PIPELINE來爬到的數據寫入本地。

但是這裡需要注意一下,

我們這裡有兩個Spider,都會往pipeline里傳item

那麼我們怎麼分別處理呢?

我查閱了一下文檔,發現並沒有什麼特別好的解決方式,

所以我就在pipeline里自己做了一個判斷,

看代碼吧:

class ProxyPipeline(object):n n 這裡我們通過對spider name的判斷n 來分清楚item是哪一個spider傳來的n 從而做出不同的處理方式n n n def process_item(self, item, spider):n if spider.name == dxdlspider:n content = item[addr].split(rn)n for line in content:n open(/Users/ehco/Desktop/result/dx_proxy.txt,a).write(line+n)nnn elif spider.name==kdlspider:n #我們直接將傳來的addr寫入文本n open(/Users/ehco/Desktop/result/kdl_proxy.txt,a).write(item[addr]+n)nn return itemn

測試一下:

啥? 為啥報錯了?

這兩個網站都不存在登錄,

所以就不是cookie的問題

那麼問題出在哪呢?

經過我仔細周密的檢查,

我發現,原來是快代理有反爬蟲機制:

請求過於頻繁的時候,禁止訪問!

上有政策,下有對策,

我們來設置一下載延遲:

DOWNLOAD_DELAY = 1n

編寫配置文件Settings:

BOT_NAME = proxynSPIDER_MODULES = [proxy.spiders]nNEWSPIDER_MODULE = proxy.spidersnROBOTSTXT_OBEY = Truen# 設置下載延遲,避免被封鎖nDOWNLOAD_DELAY = 1nITEM_PIPELINES = {n proxy.pipelines.ProxyPipeline: 300,n}n

到這裡,我們的功能就完全寫好了

代理爬到了,

剩下的就是篩選工作了。

篩選無用代理:

網上充斥著大量的代理,但

無論是免費的還是付費的其實質量都很堪憂,

所以雖然我們從網上將代理爬了下來,

如何保證這些代理都是好用的呢?

本來我們可以把驗證的過程寫在PIPELINE里,

可是驗證一個代理有效性的時機間,

比把數據寫到本地長了十幾倍,

所以我決定寫一個腳本來篩選代理。

這個腳本會用到一點多線程的知識,

說實在的,Python對於多線程和多進程的支持有點差

原來我也從來沒有這方面的需求,所以就一直沒在意這方面

這次用到了,我也是仔細學習了一下,

下面推薦一份比較好的多線程並發材料:

一行 Python 實現並行化 -- 日常多線程操作的新思路

不多說了,看代碼吧:

n我們通過這個小腳本來判斷n抓取到的ip代理是否可以用!nn還是通過我最熟悉的request庫來實現n不過這裡稍微加一下我也不太熟悉的多線程nnimport requestsn# 引入這個庫來獲得map函數的並發版本nfrom multiprocessing.dummy import Pool as ThreadPooln# 定義全局變數ndir_path = /Users/ehco/Desktop/result/nalive_ip = []nn# 使得map並發!實例化pool對象npool = ThreadPool()n# 設置並發數量!npool = ThreadPool(20)nndef test_alive(proxy):n n 一個簡單的函數,n 來判斷通過代理訪問百度n 篩選通過的代理保存到alive_ip中n n global alive_ipn #設置代理頭n proxies = {http: proxy}n print(正在測試:{}.format(proxies))n try:n r = requests.get(http://www.baidu.com, proxies=proxies, timeout=3)n if r.status_code == 200:n print(該代理:{}成功存活.format(proxy))n alive_ip.append(proxy)n except:n print(該代理{}失效!.format(proxies))nndef Out_file(alive_ip=[]):n n 將符合要求的代理寫入文件n n global dir_pathn with open(dir_path + alive_ip.txt, a+) as f:n for ip in alive_ip:n f.write(ip + n)n print(所有存活ip都已經寫入文件!)nndef test(filename=blank.txt):n # 循環處理每行文件n with open(dir_path + filename, r) as f:n lines = f.readlines()n # 我們去掉lines每一項後面的nr之類的空格n # 生成一個新的列表!n proxys = list(map(lambda x: x.strip(), [y for y in lines]))nn #一行代碼解決多線程!n pool.map(test_alive,proxys)n n # 將存活的ip寫入文件n Out_file(alive_ip)nn#調用函數!ntest(1.txt)n

代理爬取結果:

因為還沒到用代理的時候,我先爬取少量的:

篩選結果展示:

一共爬下來快200個,

能用的就這麼點,可憐吧~

這幾天我不是消失了,實在是比較忙,期末到了,各種大作業(ㄒoㄒ) 加上突發奇想,想把妹子圖全站趴下來,就又浪費了一點時間。但是放心,我不會爛尾的 逃~

先放兩張我爬妹子圖的成果:

一共3347個圖包,打包一共10g

想要資源的同學關注一下

公眾號:findyourownway

回復: 妹紙圖

公眾號里還有免費分享的ss線路,

習慣在Google查資料的小夥伴也可以關注一波!

每天的學習記錄都會 同步更新到:

微信公眾號: findyourownway

知乎專欄:從零開始寫Python爬蟲 - 知乎專欄

blog : www.ehcoblog.ml

Github: Ehco1996/Python-crawler

推薦閱讀:

1000家公司五年的新浪微博採集

TAG:Python | 爬虫 | scrapy |