repo: github.com/alphardex/p…
網路爬蟲是一種按照一定的規則,自動地抓取網站資訊的程式或者指令碼。
本文以Python語言為例簡要談談爬蟲是如何編寫的。
如何爬取網站資訊
寫爬蟲之前,我們必須確保能夠爬取目標網站的資訊。
不過在此之前必須弄清以下三個問題:
- 網站是否已經提供了api
- 網站是靜態的還是動態的
- 網站是否有反爬的對策
情形1:開放api的網站
一個網站倘若開放了api,那你就可以直接GET到它的json資料。
比如xkcd的about頁就提供了api供你下載
import requests
requests.get('https://xkcd.com/614/info.0.json').json()
複製程式碼
那麼如何判斷一個網站是否開放api呢?有3種方法:
- 在站內尋找api入口
- 用搜尋引擎搜尋“某網站 api”
- 抓包。有的網站雖然用到了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用的就是它。
比如獲取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)
框架
讀到這裡,相信你已經對網路爬蟲的結構有了個清晰的認識,可以去上手框架了。