想要用 python 做爬蟲, 是使用 scrapy框架還是用 requests, bs4 等庫?
想要用python(python3)實現一個爬蟲,來完成自己的一些需求。
參考網上的資料,發現對自己而言有兩種待選的方案:1. 使用scrapy框架 都說該框架功能強大,實現簡單。但是不兼容python3,2. 使用requests 和 bs4等庫來自己實現相比方案一,可能要自己多寫好多代碼,以及性能可能不如開源的框架。
由於自己學習的python3(好多人說python3 才是趨勢,所以沒有學習python2),如果採用方案一,會有scrapy對python3 的支持不夠好(雖說現在scrapy官網上說對python3的支持正在進行中,但不相等),希望熟悉的人回答一下 scrapy對python3的支持到底如何?; 如果採用方案二,那麼想問 ,如果我想要利用 requests, bs4等庫 實現一個簡單版的 scrapy, 困難有多大,需要學習那些東西?
真的不要糾結2還是3,對於爬蟲來講,感覺不到區別,這些都不是事兒,除了編碼和print。
而且requests和bs4都支持吧(待我確定下)。那什麼是事兒呢?
1 限制ip用requests代理,買代理,或者網上免費代理2 偽裝成瀏覽器requests切換user agent3 先登錄,保存cookiesrequests用session先post拿到cookies,再爬
4 URL參數太多,不明白什麼意思webdriver和phantomjs5 JavaScript和ajax問題瀏覽器f12分析請求規律,直接requests請求。或者用webdriver和phantomjs,如果用scrapy的話,用scrapyjs6 爬的太慢多線程,別說gil,一般是網路io慢,cpu等io7 還是慢scrapy非同步(做過幾個項目了,挺好用的),pyspider(這個支持Python3)8 還是慢分散式(暫時還沒涉及),redis,scrapyd
9 驗證碼對不起,幫不了你。簡單的可以pil,灰度二值化切割識別10 如果你想自己實現非同步請求的話grequests不錯爪機回復,待補充。ps 不知不覺自己用Python有一段時間了,寫過爬蟲,web,最近用Python掙了點錢前幾天剛剛用幾個庫自己寫了一個簡單的爬蟲,不過因為我是用的Python2.7,所以可能有些不同,先說說我的體驗
2個多月前學習了Scrapy框架,之後自己寫了幾個爬蟲,基本是BaseSpider,CrawlSpider,當時感覺寫一個爬蟲很簡單,有一個現成的框架擺在那裡,只要自己定義要抓取的類和抓取的函數就行了
之後由於其他事情Python學習斷了一個多月,之後看《Python核心編程》,講到爬蟲,就想到為什麼不自己寫一個,於是開始做。
這時候才體會到寫爬蟲並不像自己想的那麼簡單,得自己定義諸如存儲數據類,同域名保留函數,數據去重等一系列問題,最後用兩種方案寫出來,一個是定義一個類,一個是只用函數,不過二者基本上是類似的,當然還有一系列問題沒有解決,目前的功能是根據輸入的網址和爬取深度來爬取網址,不過基本雛形出來了,以後慢慢解決
個人建議先學習Scrapy,我能感受到的最大的好處就是學習了正則,以至於後來自己寫爬蟲提取網址直接用正則了,其他的什麼庫都沒有用
學完Scrapy後,試著自己寫一個爬蟲,因為這時候你對爬蟲的基本操作流程已經有所掌握,照貓畫虎還不會么,安題主所說,用request和bs4庫是肯定不夠的,不過不要急著學庫,到時候需要了再去查(我個人是喜歡用正則,所以我自己寫的爬蟲只是用了re,當然不可否認上面兩個也很強大,個人喜好而已)寫的過程肯定會遇到問題,比如數據存放,去重,抓取,一個一個解決,對提升自己絕對有好處
看著自己寫的爬蟲跑網頁,也是很有成就感的個人建議還是先使用scrapy快速上手寫幾個爬蟲出來,再學習使用requests+bs4自己寫爬蟲。
原因如下:
1、學習一個新東西,首先是先用起來,然後在使用中發現問題,再究其原理,才能深入學習;2、scrapy不管是否支持python3,如果想學習爬蟲原理,都無礙的,因為學習思想最重要;3、scrapy封裝了爬蟲的一些核心組件,而且上手簡單,如果想以後自己寫爬蟲框架,它的實現思路還是很值得借鑒的;等你用scrapy寫出幾個爬蟲抓幾個網站後,這基本算是入門了。
等你要抓的網站非常多時,就會遇到幾個問題:
1、一些網站開始防抓,IP被封?
隨機User-Agent,隨機代理,開始用到scrapy的插件。2、網頁太多,抓的太慢,scrapy默認是不支持分散式的,怎麼實現分散式?
一些分散式的插件就會用起來,例如scrapy-redis。3、網頁越來越多,會不會抓重複?
哦,原來不會重複抓。看一看scrapy源碼,基於url指紋過濾重複的。啊,過濾規則自己可以替換,不錯!4、網站如何深度抓取,如何廣度抓取?
看一看scrapy源碼,哦,原來通過實現了棧和隊列改變任務的入隊順序,結合配置來控制。如果你有足夠的興趣和耐心,有沒有發現,從開始使用它,慢慢地你開始關注scrapy的是如何實現了,繼續深入源碼,你就會發現它的實現思想很巧妙,代碼結構低耦合,插件威力巨大!
好了,下一步你就可以構建自己的爬蟲框架了。
為什麼要自己寫?
1、覺得scrapy很多功能用不到?自己喜歡造輪子?
理解了它的原理,自己精簡寫一個,還不容易?2、覺得scrapy的一些功能沒有實現?
例如,如何實現增量抓取?如何基於資料庫的任務調度和數據存儲?如何分散式抓取?如何做可視化監控?3、平時很常用的scrapy插件,太多,太散?
自己封裝常用插件、形成組件化,快速配置。其實這每一步都是學習、思考、再學習的過程,從使用框架、學習框架、到自己寫框架,並不是那麼難。
我當初就是以這樣一個思路學習爬蟲,深入爬蟲的。
附上自己的當初(一年前)學習scrapy源碼時,抽離和精簡出的scrapy架構,並且用gevent替換了twisted,自己實現了一套簡版的mini-scrapy,僅供學習使用。
github地址:https://github.com/kaito-kidd/mini-scrapy註:不更新,僅供學習使用。聽我說:一開始千萬不要用框架,不管是Scrapy還是什麼其他框架。
你就老實的用Requests、用BeautifulSoup4、用lxml、用正則表達式、用多線程、用非同步、用分散式如果你需要的話、用代理設計代理策略、自己設計抓取策略。
然後突然有一天你上手了Scrapy框架,你感覺發現了新大陸,漸漸的你不滿足於Scrapy的速度,你開始讀它的源碼,你發現它的策略有不足之處,你竟然能改造這個框架了。
很多人問我如何學習Python爬蟲,為此我整理編寫了一本Python爬蟲相關的電子書,主要包括Python入門、Python爬蟲入門到進階、Python爬蟲面試總結等等。可以在微信公眾號【一個程序員的日常】後台回復關鍵詞【1】獲取這本電子書。
不知道樓主水平如何,冒昧答一下。
scrapy 的實現對初學者來說並不簡單,scarpy 採用了 twisted 框架,使用了 actor model,是一個非同步的消息驅動的系統,如果對這塊還不了解,那想了解 scrapy 得先了解這些。
參考這裡:Scrapy源碼分析(一)架構概覽
爬蟲基本原理很簡單,不用局限於 scrapy。無非是一個有向圖的遍歷。對爬蟲來說,性能一般不是問題,要防止的主要是封禁方面的問題。
參考這裡:爬蟲的基本框架 - ospider - 博客園
順便安利下基於 Python 3 Asyncio 寫的爬蟲:yifeikong/aiospider
入門用requests或者urllib,畢竟調試起來方便,可以一行一行調試,看看運行結果,容易讓你入門。等你有更高的需求,比如爬的深度比較深,有高並發需求,或者要面向資料庫再去學scrapy。另,scrapy支持python3的,還有就是request是實現不了scrapy的,等你學到非同步就明白了。你可以試著用aiohttp實現scrapy,這是一個大坑。
如果只是工作的一個需求,那就直接上框架。
這是解決問題,不是秀技術,不是非得自己造輪子。
時間也是成本。在這個言必稱「大數據」「人工智慧」的時代,數據分析與挖掘(比如爬蟲)可以說互聯網從業者必備的技能。想要用Python做爬蟲,使用scrapy框架是很好的選擇。這次我拉來了我們豈安科技喜歡(瞎)折騰的研發工程師Hekko,跟知友說說利用輕量級爬蟲框架scrapy來進行數據採集的基本方法。基本保證人人都會吧。以下,GO~
一、scrapy簡介
scrapy是一套用Python編寫的非同步爬蟲框架,基於Twisted實現,運行於Linux/Windows/MacOS等多種環境,具有速度快、擴展性強、使用簡便等特點。即便是新手也能迅速掌握並編寫出所需要的爬蟲程序。scrapy可以在本地運行,也能部署到雲端(scrapyd)實現真正的生產級數據採集系統。
我們通過一個實例來學習如何利用scrapy從網路上採集數據。「博客園」是一個技術類的綜合資訊網站,本次我們的任務是採集該網站MySQL類別 https://www.cnblogs.com/cate/mysql/ 下所有文章的標題、摘要、發布日期、閱讀數量,共4個欄位。最終的成果是一個包含了所有4個欄位的文本文件。如圖所示:
最終拿到的數據如下所示,每條記錄有四行,分別是標題、閱讀數量、發布時間、文章摘要:
二、安裝scrapy
下面來看看怎麼安裝scrapy。首先你的系統里必須得有Python和pip,本文以最常見的Python2.7.5版本為例。pip是Python的包管理工具,一般來說Linux系統中都會默認安裝。在命令行下輸入如下命令並執行:
sudo pip install scrapy -i http://pypi.douban.com/simple –trusted-host=pypi.douban.com
pip會從豆瓣網的軟體源下載並安裝scrapy,所有依賴的包都會被自動下載安裝。」sudo」的意思是以超級用戶的許可權執行這條命令。所有的進度條都走完之後,如果提示類似」Successfully installed Twisted, scrapy … 「,則說明安裝成功。
三、scrapy交互環境
scrapy同時也提供了一個可交互運行的Shell,能夠供我們方便地測試解析規則。scrapy安裝成功之後,在命令行輸入 scrapy shell 即可啟動scrapy的交互環境。scrapy shell的提示符是三個大於號&>&>&>,表示可以接收命令了。我們先用fetch()方法來獲取首頁內容:
&>&>&> fetch( 「https://www.cnblogs.com/cate/mysql/」 )
如果屏幕上有如下輸出,則說明網頁內容已經獲取到了。
2017-09-04 07:46:55 [scrapy.core.engine] INFO: Spider opened
2017-09-04 07:46:55 [scrapy.core.engine] DEBUG: Crawled (200)
&
獲取到的響應會保存在response對象中。該對象的status屬性表示HTTP響應狀態,正常情況為200。
&>&>&> print response.status
200
text屬性表示返回的內容數據,從這些數據中可以解析出需要的內容。
&>&>&> print response.text
u"&
&
&
&
&
&
&
&』
可以看到是一堆很亂的HTML代碼,沒法直觀地找到我們需要的數據。這個時候我們可以通過瀏覽器的「開發者工具」來獲取指定數據的DOM路徑。用瀏覽器打開網頁 https://www.cnblogs.com/cate/mysql/ 之後,按下F12鍵即可啟動開發者工具,並迅速定位指定的內容。
可以看到我們需要的4個欄位都在 / body / div(id=」wrapper」) / div(id=」main」) / div(id=」post_list」) / div(class=」post_item」) / div(class=」post_item_body」) / 下,每一個」post_item_body」都包含一篇文章的標題、摘要、發布日期、閱讀數量。我們先獲取所有的」post_item_body」,然後再從裡面分別解析出每篇文章的4個欄位。
&>&>&> post_item_body = response.xpath( 「//div[@id=』wrapper』]/div[@id=』main』]/div[@id=』post_list』]/div[@class=』post_item』]/div[@class=』post_item_body』]」 )
&>&>&> len( post_item_body )
20
response的xpath方法能夠利用xpath解析器獲取DOM數據,xpath的語法請參考官網文檔。可以看到我們拿到了首頁所有20篇文章的post_item_body。那麼如何將每篇文章的這4個欄位提取出來呢?
我們以第一篇文章為例。先取第一個post_item_body:
&>&>&> first_article = post_item_body[ 0 ]
標題在post_item_body節點下的 h3 / a 中,xpath方法中text()的作用是取當前節點的文字,extract_first()和strip()則是將xpath表達式中的節點提取出來並過濾掉前後的空格和回車符:
&>&>&> article_title = first_article.xpath( 「h3/a/text()」 ).extract_first().strip()
&>&>&> print article_title
Mysql之表的操作與索引操作
然後用類似的方式提取出文章摘要:
&>&>&> article_summary = first_article.xpath( 「p[@class=』post_item_summary』]/text()」 ).extract_first().strip()
&>&>&> print article_summary
表的操作: 1.表的創建: create table if not exists table_name(欄位定義); 例子: create table if not exists user(id int auto_increment, uname varchar(20), address varch …
在提取post_item_foot的時候,發現提取出了兩組內容,第一組是空內容,第二組才是「發佈於 XXX」的文字。我們將第二組內容提取出來,並過濾掉「發佈於」三個字:
&>&>&> post_date = first_article.xpath( 「div[@class=』post_item_foot』]/text()」 ).extract()[ 1 ].split( 「發佈於」 )[ 1 ].strip()
&>&>&> print post_date
2017-09-03 18:13
最後將閱讀數量提取出來:
&>&>&> article_view = first_article.xpath( 「div[@class=』post_item_foot』]/span[@class=』article_view』]/a/text()」 ).extract_first()
&>&>&> print article_view
閱讀(6)
很多人覺得xpath方法里的規則太過複雜。其實只要了解一點HTML文件的DOM結構,掌握xpath的提取規則還是比較輕鬆容易的。好在 scrapy shell 允許我們反覆對DOM文件進行嘗試解析。實驗成功的xpath表達式就可以直接用在項目里了。
四、創建scrapy項目
scrapy shell 僅僅適用於測試目標網站是否可以正常採集以及採集之後如何解析,真正做項目的時候還需要從頭建立一個scrapy項目。 輸入以下命令退出 scrapy shell 並返回Linux命令行:
&>&>&> exit()
假設我們的項目名稱叫 cnblogs_scrapy ,則可通過下面的命令來創建一個 scrapy 項目:
scrapy startproject cnblogs_scrapy
會自動生成如下結構的目錄與文件:
|– cnblogs_scrapy
| |– __init__.py
| |– items.py
| |– middlewares.py
| |– pipelines.py
| |– settings.py
| `– spiders
| `– __init__.py
`– scrapy.cfg
五、解析與存儲
我們需要改三個地方:
1)在spiders目錄下新建一個文件cnblogs_mysql.py,內容如下:
# -*- coding: utf-8 -*-
import scrapy
import sys
reload( sys )
sys.setdefaultencoding( "utf8" )
class CnblogsMySQL(scrapy.Spider):
# 爬蟲的名字,必須有這個變數
name = "cnblogs_mysql"
page_index = 1
# 初始地址,必須有這個變數
start_urls = [
"https://www.cnblogs.com/cate/mysql/" + str( page_index ),
]
def parse(self, response):
post_items = response.xpath(
"//div[@id="wrapper"]/div[@id="main"]/div[@id="post_list"]/div[@class="post_item"]/div[@class="post_item_body"]"
)
for post_item_body in post_items:
yield {
"article_title":
post_item_body.xpath( "h3/a/text()" ).extract_first().strip(),
"article_summary":
post_item_body.xpath( "p[@class="post_item_summary"]/text()" ).extract_first().strip(),
"post_date":
post_item_body.xpath( "div[@class="post_item_foot"]/text()" ).extract()[ 1 ].strip(),
"article_view" :
post_item_body.xpath(
"div[@class="post_item_foot"]/span[@class="article_view"]/a/text()"
).extract_first().strip()
}
next_page_url = None
self.page_index += 1
if self.page_index &<= 20:
next_page_url = "https://www.cnblogs.com/cate/mysql/" + str( self.page_index )
else:
next_page_url = None
if next_page_url is not None:
yield scrapy.Request(response.urljoin(next_page_url))
這個就是我們的爬蟲,其中name和start_urls兩個變數必須存在。parse方法的作用是將響應內容解析為我們需要的數據。parse中的for循環就是在提取每一頁中的20篇文章。解析並提取完成後,通過yield將結果拋到pipeline進行存儲。
2)修改pipelines.py文件,內容如下:
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don"t forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
class CnblogsScrapyPipeline(object):
def open_spider( self, spider ):
self.fp = open( "data.list", "w" )
def close_spider( self, spider ):
self.fp.close()
def process_item(self, item, spider):
self.fp.write( item[ "article_title" ] + "
" )
self.fp.write( item[ "article_view" ] + "
" )
self.fp.write( item[ "post_date" ] + "
" )
self.fp.write( item[ "article_summary" ] + "
" )
return item
可以看到有三個方法。這三個方法是從基類中繼承而來。
open_spider/close_spider分別在爬蟲啟動和結束的時候執行,一般用作初始化及收尾。process_item會在每一次spider解析出數據後yield的時候執行,用來處理解析的結果。上面這個pipeline的作用是將每一條記錄都存儲到文件中。當然也可以通過pipeline將內容存儲到資料庫或其它地方。
3)配置pipeline
注意僅僅有這個pipeline文件還不能工作,需要在配置文件中向scrapy聲明pipeline。同目錄下有個settings.py文件,加入如下內容:
ITEM_PIPELINES = {
"cnblogs_scrapy.pipelines.CnblogsScrapyPipeline": 300,
}
後面的數字是pipeline的權重,如果一個爬蟲有多個pipeline,各個pipeline的執行順序由這個權重來決定。
修改完成並保存之後,退到cnblogs_scrapy的上層目錄,並輸入以下命令啟動爬蟲:
scrapy crawl cnblogs_mysql
所有經過處理的信息都會輸出到屏幕上。結束之後,當前目錄中會生成名為data.list的文件,裡面存儲了本次採集的所有數據。
六、翻頁
cnblogs_mysql.py的parse方法中有個next_page_url變數,一般情況下這個變數的內容應當是當前頁面的下一頁URL,該URL當然也可以通過解析頁面來獲取。獲得下一頁的URL之後,用scrapy.Request來發起新一次的請求。 簡單起見本文通過直接拼接URL的形式來指定僅採集前20頁的數據。
七、其它
用scrapy發請求之前,也可以自己構造Request,這樣就能偽裝為真實訪問來避免被封。一般情況下有修改User-Agent、隨機採集時間、隨機代理IP等方法。 scrapy項目可以直接運行,也可以部署在雲端進行批量採集和監控。雲端部署需要用到scrapyd,操作起來也很簡單,有需要的話可自行參考官網文檔。
看你使用場景。
如果你的爬蟲是玩玩,練練手。或者是對某一站點請求並發量不大的時候,可以用scrapy。如果你的爬蟲對某一站點請求很頻繁,量很大時,我傾向於使用requests bs re。爬蟲的業務邏輯很簡單。重點是反爬!反爬!反爬!
scrapy優勢在於抽象了業務,讓你通過配置你需要的數據格式,幫你快速獲取結果。這在請求量很小的時候還算方便,但當請求量一大起來,必然會遇到反爬機制各種封你,對於反爬scrapy沒提供特別有效的處理機制。
另外往往獲取有效數據的操作,用BeautifulSoup+re就搞定了,而為了使用scrapy不得不配置的一堆東西反倒顯得繁瑣了。既然所有反爬的處理都需要自己弄,這樣看來scrapy的優勢其實已經很小了,所以我建議requests bs re做。不要糾結python2 還是python3 的問題。
學習編程不光是學習語法,是學習計算思維,編程思路。python2和python3 差別不是很大。看你的情況,建議先學習標準庫或requests 這個庫學習爬蟲,先學會抓包,模擬post、get ,自動填表等基本技能,再學習scrapy框架。
建議看看 黃哥主講的python爬蟲聯想詞視頻,學習一下基礎知識。
搜索「python爬蟲聯想詞視頻」 有播放地址。
加油!先去試試urllib和urllib2,熟悉一下爬蟲的基本思維。然後熟悉了大概之後看看requests,這也是urlliburllib2封裝的,熟悉抓包和分析頁面成分,了解POST、GET都是什麼原理和實用,試著自己去寫幾個小站的爬蟲,當你不滿足於此的時候可以去擼Scrapy了,但是入坑之前推薦樓主先去了解Python的多線程處理,目前我正在死磕中。。
比較複雜的用lxml代替bs4,xpath方便
requests和bs4庫還是相當強大的,簡單寫個幾十行,再配上代理和多進程/多線程,就能抓取相當可觀的數據。題主如果想入門這兩個庫可以在網易雲課堂上搜一個有關python爬蟲的課程,具體名字忘了,但是個人認為講的還不錯。另外就是善用文檔,一切說明都在文檔里,百度一搜就有。
是都得會
很多人說先不要用框架,熟悉了相關庫再用框架。但是作為使用者。拿來主義更加重要。不然用什麼Python?對於未接觸過相關框架的用戶,稍微熟悉下幾個http庫有必要,對於用過django.之類框架的有經驗用戶,直接scrapy 好了!
用scrapy,比較方便基本上直接填代碼不需要考慮架構問題。http://www.bestblog.top/2017/08/24/Scrapy%E7%AC%AC%E4%B8%80%E6%88%98%E2%80%94%E7%88%AC%E5%8F%96%E6%99%BA%E8%81%94%E6%8B%9B%E8%81%98/
這個問題跟出門該坐公交還是地鐵有什麼本質區別?答案是,看情況,看需求。
一開始不要上框架,會讓你雲里霧裡,掩蓋了真相。
最近正好剛完成我的本科畢設,裡面需要寫爬蟲爬一些數據,主要是幾個社交網站的數據,Instagram、Facebook什麼的。簡單說說我這過程中的一點點經驗吧。
之前本科基本上就能寫寫java,熟悉一點MVC吧,然後拿到這個畢設題目之後決定從零開始學Python和爬蟲,學了學scrapy,還有題主說到的那些庫,這算是背景吧。
我是感覺先從這些基本的庫的使用入手比較好啦。其實我論文里寫基於scrapy並不是完全正確的。我只是建立了一個scrapy項目,然後利用了一下裡面的items啊pipelines啊之類的比較基礎的東西,很多內容其實都是靠題主說的那些庫各種搭配組合實現的。
一開始我是先學了幾個基本的東西比如bs4什麼的,然後發現哇有框架啊來來來用起來,結果有的時候使用框架會出現「錯了,這到底是為啥。。對了,這又是為啥」的問題。。看源碼又不太看得懂畢竟還屬於Python小白,直接讀框架什麼的還是有點吃力,所以只能勉勉強強學一點框架很基礎的用法,甚至都不能說很會用。這樣反而會難以實現我的目的,只好回到基本的requests什麼的。。
而這些零零碎碎庫會提供很多有用的基本的函數,偶爾不了解的去讀一下源碼也就能了解了,感覺比框架更簡單一點,至少,就算不太理解原理,也能更快的用起來啊~然後一個好處就是可以根據自己的需要各種搭配,換著花樣爬,不一樣的網站可以用不一樣的策略。所有這些,我覺得都算是對爬蟲理念的理解的加深的過程吧。
熟悉了各個獨立地相關庫的原理之後,我覺得等我以後還有機會寫爬蟲的話,應該就會開始朝著使用框架並且理解框架的方向努力了,總之,我覺得,框架可能容易上手(其實也沒有啊我覺得)但很難搞得精通,不如由淺入深,從簡單的庫開始~
可能題主的具體情況和我不盡相似,我也就只是大白話地簡單說了一點,算是自己這段時間的感覺吧,還希望能給題主一點點幫助哈~一般來說呢 建議先用request bs4之類的寫一個爬蟲 當作入門級別 主要是弄明白數據的傳輸如(post和get)還有基本的網頁解析和數據提取過程然後寫了五六個之後 想要提升速度 可以直接嘗試scrapy 但只能一步步看官方文檔 別無他法 遇到不懂google或者stackoverflow 祝好
推薦閱讀:
※Python 在 Linux 系統運維中都有哪些應用?
※Python 關於讀寫txt的問題?
※Python Shell 中敲擊方向鍵顯示「^[[C^[[D」,原因是什麼?如何修復?
※為什麼python代碼有時候在命令行下和Python Shell中執行的結果不一樣呢 ?
※Python 曾經開發過哪些了不起的程序或遊戲?