![]() |
VOOZH | about |
如今,網上的爬蟲教程可謂是泛濫成災了,從urllib開始講,最後才講到requests和selenium這類高級庫,實際上,根本就不必這麼費心地去了解這麼多無謂的東西的。只需記住爬蟲總共就三大步驟:發起請求——解析數據——存儲數據,這樣就足以寫出最基本的爬蟲了。諸如像Scrapy這樣的框架,可以說是集成了爬蟲的一切,但是新人可能會用的不怎麼順手,看教程可能還會踩各種各樣的坑,而且Scrapy本身體積也有點大。因此,本人決定親手寫一個輕量級的爬蟲框架————looter,裡面集成了調試和爬蟲模板這兩個核心功能,利用looter,你就能迅速地寫出一個高效的爬蟲。另外,本項目的函數文檔也相當完整,如果有不明白的地方可以自行閱讀源碼(一般都是按Ctrl+左鍵或者F12)。
安裝
$pipinstalllooter
僅支持Python3.6及以上版本。
快速開始
讓我們先來擼一個非常簡單的圖片爬蟲:首先,用shell獲取網站
$lootershellkonachan.com/post
然後用2行代碼就可以將圖片抓取到本地
imgs=tree.cssselect('a.directlink')save_imgs(imgs)
或者只用1行也行:d
save_imgs(links(res,search='jpg'))
如果想要看更多的爬蟲例子,猛戳這裡(裡面有驚喜哦)
工作流
如果你想迅速擼出一個爬蟲,那麼你可以用looter提供的模板來自動生成一個
$lootergenspidernametmpl[--async]
在這行代碼中,tmpl是模板,分為data和image兩種模板。
async是一個備用的選項,它使得生成的爬蟲核心用asyncio而非線程池。
在生成的模板中,你可以自定義domain和tasklist這兩個變量。
什麼是tasklist?實際上它就是你想要抓取的頁面的所有連結。
以http://konachan.com為例,你可以使用列表推導式來創建自己的tasklist:
domain='https://konachan.com'tasklist=[f'{domain}/post?page={i}'foriinrange(1,9777)]
然後你就要定製你的crawl函數,這是爬蟲的核心部分。
defcrawl(url):
tree=lt.fetch(url)
items=tree.cssselect('ulli')foriteminitems:
data=dict#data[...]=item.cssselect(...)
pprint(data)
在大多數情況下,你所要抓取的內容是一個列表(也就是HTML中的ul或ol標籤),可以用css選擇器將它們保存為items變量。
然後,你只需使用for循環來疊代它們,並抽取你想要的數據,將它們存儲到dict中。
但是,在你寫完這個爬蟲之前,最好用looter提供的shell來調試一下你的cssselect代碼是否正確。(目前已集成ptpython,一個支持自動補全的REPL)
items=tree.cssselect('ulli')item=items[0]item.cssselect(anythingyouwanttocrawl)#注意代碼的輸出是否正確!
調試完成後,你的爬蟲自然也就完成了。怎麼樣,是不是很簡單:)
函數
looter為用戶提供了很多實用的函數。
view
在爬取頁面前,你最好確認一下頁面的渲染是否是你想要的
view(url)
save_imgs
當你獲取了一堆圖片連結時,用它可以直接將它們保存到本地
img_urls=[...]save_imgs(img_urls)
alexa_rank
可以獲取網站的reach和popularity指數(人氣度),此函數返回一個元組(url, reach_rank, popularity_rank)
alexa_rank(url)
links
獲取網頁的所有連結
links(res)#獲取所有連結links(res,absolute=True)#獲取絕對連結links(res,search='text')#查找指定連結
同樣地,你也可以用正則表達式來獲取匹配的連結
re_links(res,r'regex_pattern')
save_as_json
將所得結果保存為json文件,支持按鍵值排序
total=[...]save_as_json(total,name='text',sort_by='key')
parse_robots
用於爬取網站robots.txt上的所有連結。這個在做全站爬蟲或者遞歸式url爬蟲時頗為有效
parse_robots(url)
login
有一些網站必須要先登錄才能爬取,於是就有了login函數,本質其實就是建立session會話向伺服器發送帶有data的POST請求。 考驗各位抓包的能力,以下為模擬登錄網易126郵箱(要求參數:postdata和param)
params={'df':'mail126_letter','from':'web','funcid':'loginone','iframe':'1','language':'-1','passtype':'1','product':'mail126','verifycookie':'-1','net':'failed','style':'-1','race':'-2_-2_-2_db','uid':'webscraping123@126.com','hid':'10010102'}postdata={'username':你的用戶名,'savelogin':'1','url2':'http://mail.126.com/errorpage/error126.htm','password':你的密碼}url=https://mail.126.com/entry/cgi/ntesdoor?res,ses=login(url,postdata,params=params)#res為post請求後的頁面,ses為請求會話index_url=re.findall(r'href=(.*?)',res.text)[0]#在res中獲取重定向主頁的連結index=ses.get(index_url)#用ses會話訪問重定向連結,想確認成功的話print下即可
防反爬蟲技巧
· 延遲爬取:time.sleep(n)
· 代理IP池:scylla
· 動態JS網頁:requestium或抓包
· 模擬登陸:fuck-login
· 驗證碼:Tesseract、OpenCV、Keras、打碼平台
api搭建
有時候,僅僅爬取數據存到資料庫里是不夠的。如果想把數據開放出去,就需要搭建api。一旦建成,你就可以以網頁、app甚至是微信小程序的形式來向他人展現和使用你的數據了。
利用一個叫eve的框架,我們就能迅速搭建出我們的api
$pipinstalleve
假設你已經利用爬蟲爬取到了jav的數據並存入了MongoDB資料庫中,那麼搭建api就只需創建2個文件:一個是api的站點文件(本質上是一個flask的app實例),另一個是api的配置文件。
jav_api.py
fromeveimportEve
app=Eve(settings='jav_settings.py')if__name__=='__main__':
app.run
jav_settings.py
#validationrules:http://docs.python-cerberus.org/en/stable/validation-rules.htmljav={'datasource':{'source':'torrents','default_sort':[('date',-1)]
}
}
ALLOW_UNKNOWN=TrueDOMAIN={'jav':jav}
MONGO_DBNAME='jav'MONGO_QUERY_BLACKLIST=['$where']
RENDERERS=['eve.render.JSONRenderer']
其中datasource引用了jav資料庫中的torrents集合,並將數據根據日期降序排序。
運行jav_api.py,並訪問這個連結,就能看見我們搭建的api了。
如果想進行查詢操作,用where加上正則表達式就可以了(其實就是MongoDB的查詢語法)
http://127.0.0.1:5000/jav?where={name:{$regex:波多}}
如果想要搭建更健全的RESTful api,建議閱讀eve的官方文檔。
至此,我們的api便搭建完成了:)