網路爬蟲精要

alphardex發表於2019-04-27

repo: github.com/alphardex/p…

網路爬蟲是一種按照一定的規則,自動地抓取網站資訊的程式或者指令碼。

本文以Python語言為例簡要談談爬蟲是如何編寫的。

如何爬取網站資訊

寫爬蟲之前,我們必須確保能夠爬取目標網站的資訊。

不過在此之前必須弄清以下三個問題:

  1. 網站是否已經提供了api
  2. 網站是靜態的還是動態的
  3. 網站是否有反爬的對策

情形1:開放api的網站

一個網站倘若開放了api,那你就可以直接GET到它的json資料。

比如xkcd的about頁就提供了api供你下載

import requests
requests.get('https://xkcd.com/614/info.0.json').json()
複製程式碼

那麼如何判斷一個網站是否開放api呢?有3種方法:

  1. 在站內尋找api入口
  2. 用搜尋引擎搜尋“某網站 api”
  3. 抓包。有的網站雖然用到了ajax(比如果殼網的瀑布流文章,亦或是unsplash的瀑布流圖片),但是通過抓包還是能夠獲取XHR裡的json資料的,不要傻乎乎地去用selenium,反而會降低效率。

怎麼抓包:F12 - Network - F5重新整理

實際上,app的資料也可以通過抓包來獲取。

app抓包

安裝fiddler並啟動,開啟Tools-Options-Connections,將Allow remote computers to connect打上勾並重啟fiddler。

命令列上輸入ipconfig,檢視自己網路的ipv4地址,在手機的網路上設定HTTP代理,埠為8888。

這時雖說能抓到資料,但都是HTTP的,而app的大部分資料都是HTTPS的。

在Options-HTTPS中將Decrypt HTTPS traffic打上勾。

以ios系統為例,在Safari瀏覽器中輸入http://ipv4:8888,下載證照並安裝。

這樣就能抓到HTTPS資料啦!

情形2:不開放api的網站

如果此網站是靜態頁面,那麼你就可以解析它的HTML。

解析庫強烈推薦parsel,不僅語法和css選擇器類似,而且速度也挺快,Scrapy用的就是它。

你需要了解一下css選擇器的語法xpath也行),並且學會看網頁的審查元素

比如獲取konachan的所有原圖連結

from parsel import Selector
res = requests.get('https://konachan.com/post')
tree = Selector(text=res.text)
imgs = tree.css('a.directlink::attr(href)').extract()
複製程式碼

如果此網站是動態頁面,先用selenium來渲染JS,再用HTML解析庫來解析driver的page_source。

比如獲取hitomi.la的資料(這裡把chrome設定成了無頭模式)

from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.get('https://hitomi.la/type/gamecg-all-1.html')
tree = Selector(text=driver.page_source)
gallery_content = tree.css('.gallery-content > div')
複製程式碼

情形3:反爬的網站

目前的反爬策略常見的有:驗證碼、登入、封ip等。

驗證碼:利用打碼平臺破解(如果硬上的話用opencv或keras訓練圖)

登入:利用requests的post或者selenium模擬使用者進行模擬登陸

封ip:買些代理ip(免費ip一般都不管用),requests中傳入proxies引數即可

其他防反爬方法:偽裝User-Agent,禁用cookies等

如何編寫結構化的爬蟲

爬蟲的結構很簡單,無非就是創造出一個tasklist,對tasklist裡的每一個task呼叫crawl函式。

大多數網頁的url構造都是有規律的,你只需根據它用列表推倒式來構造出tasklist

對於那些url不變的動態網頁,先考慮抓包,不行再用selenium點選下一頁

如果追求速度的話,可以考慮用concurrent.futures或者asyncio等庫。

import requests
from parsel import Selector
from concurrent import futures

domain = 'https://www.doutula.com'

def crawl(url):
    res = requests.get(url)
    tree = Selector(text=res.text)
    imgs = tree.css('img.lazy::attr(data-original)').extract()
    # save the imgs ...


if __name__ == '__main__':
    tasklist = [f'{domain}/article/list/?page={i}' for i in range(1, 551)]
    with futures.ThreadPoolExecutor(50) as executor:
        executor.map(crawl, tasklist)
複製程式碼

資料儲存的話,看需求,存到資料庫中的話只需熟悉對應的驅動即可。

常用的資料庫驅動有:pymysql(MySQL), pymongo(MongoDB)

框架

讀到這裡,相信你已經對網路爬蟲的結構有了個清晰的認識,可以去上手框架了。

looter是本人寫的一個輕量級框架,適合中小型專案;比較大型的專案建議用scrapy

相關文章