使用Python實現豆瓣閱讀書籍信息的獲取

最近一直在看Python方面的知識,包括數據分析中常用的numpy、pandas、scipy等模塊;資料庫API介面,如常見的pymysql、pymssql等模塊;爬蟲方面所需要的urllib、bs4等模塊;還有正則表達式re模塊。在之前的幾期中我們已經詳細介紹了numpy、pandas和pymysql、pymssql模塊的應用,具體可參見下文:

Python數據分析之numpy學習(一)

Python數據分析之numpy學習(二)

Python數據分析之pandas學習(一)

Python數據分析之pandas學習(二)

利用Python讀取外部數據文件

今天我們就來講講有關爬蟲的一點點知識和應用,文章內容相對簡單,可操作比較強,後期我也將會更加深入的挖掘Python實現爬蟲的方法和應用。接下來我們就以一個例子開始吧。

豆瓣是我常去的一個網站,上面提供了圖書、電影、音樂等方面的推薦、評論和價格比較。如果我需要在買一本Python方面的書,我會去豆瓣看看都有哪些被推薦的書,以及這些書的評分、評價等,從而最終確定我該買那本書。下面這幅圖就是豆瓣閱讀中搜索Python的返回信息:

於是我突發奇想,是否可以將自己學習的urllib、bs4和pymysql模塊應用於一個簡單的爬蟲呢?將這些書籍的名稱、作者、價格、分類、評分等信息爬取下來,並存放到資料庫中。於是我開始動手準備,為完成這個簡單的爬蟲,我所使用的工具是Python3.5和MySQL5.6。

導入開發所需的模塊

In [1]: import urllib.requestnIn [2]: from bs4 import BeautifulSoupnIn [3]: import pymysqln

我們以url為豆瓣閱讀搜索:為例,實際上我搜出來的有3頁,隨後通過循環的方式一次性爬取3個頁面的內容,這裡先以第一頁的內容為例,看看如何爬取該頁面的內容。

使用urllib的子模塊request中的urlopen方法打開源代碼,並使用read方法將源代碼讀取下來:

In [4]: url = https://read.douban.com/search?q=Python&start=0nIn [5]: content = urllib.request.urlopen(url).read()n

#列印內容

In [6]: print(content)n

發現一個非常嚴重的問題:所有的中文都沒有能夠正常的顯示出來!沒關係,我們只需要將content的字符集改為utf8即可。

In [7]: content = content.decode(utf-8)nnIn [8]: print(content)n

哈哈,這會中文都回來了吧~

接下來我們就使用bs4模塊下的BeautifulSoup函數解析上面讀取下來的網頁內容,並通過prettify的方法將網頁內容以嵌套的方式列印出來,顯得好看一些。

In [9]: soup = BeautifulSoup(content,html.parser)nnIn [10]: print(soup.prettify())n

非常好!接下來就是我該如何截取出我想搜集的欄位內容,如書的名稱、作者等信息。如果你使用Chrom瀏覽器的話,你可以通過右擊的方式,選擇「審查元素」,就可以進入下圖所示的頁面。具體操作如下:

1)點擊搜索圖標;

2)選擇需要爬取的大塊內容,如頁面中第一本書的所有信息;

3)回到下方的網頁源代碼,逐個展開你就會發現具體的類、標籤所對應的書本信息,而且最下方也會顯示div.info的字樣哦。這個字樣就是告訴你,這一本書的內容全部包含在class為info的標籤裡面。

好了,知道如何獲取整本書的class了,接下來就是看每一個所需信息的標籤是什麼就可以啦。方法類似,你不妨試試~如有問題可以聯繫我。

下面我們使用select方法抓取出書本的相關信息,由於這一個頁面中,有10本書,所以就需要通過循環的方式把這一頁所有書籍的相關信息抓取出來:

In [12]: for content in soup.select(.info): #info為大塊內容對應的classn ...: title = content.select(.title)[0].text #titlew為書籍名稱對應的classn ...: author = content.select(.author-item)[0].textn ...: price = content.select(.price-tag)[0].textn ...: category = content.select(.category)[0].text[3:]n ...: rating = content.select(.rating-average)[0].textn ...: eveluate_nums = content.select(.ratings-link)[0].text[:-3]n ...: desc = content.select(.article-desc-brief)[0].textn ...: nn ...: print(title,author,price,category,rating,eveluate_nums,desc)n

是不是很興奮!一下子就把這一個頁面的內容全部抓取下來了,接下來是不是該處理第二頁的內容啦,方法還是一樣一樣的,只要最後將所有頁的內容拼接起來就OK了。你當我傻啊!這要是有個上百頁上千頁的,我一個星期都在搞這個,是不是效率太低了!唉~我們接下來只要發現每一頁url的規律是不是就可以通過循環的方式解決這個一頁一頁處理的笨方法啦。我們發現原來這三個頁面的url是這樣的:

豆瓣閱讀搜索:

豆瓣閱讀搜索:

豆瓣閱讀搜索:

規律很明顯,就不說啦!這裡繼續上代碼,實現翻頁般的爬蟲:

生成有規律的url:

In [13]: urls = []n ...: for i in (0,10,20):nn ...: urls.append(https://read.douban.com/search?q=Python&start= + str(i))n

In [15]: for url in urls:n ...: #讀取網頁內容n ...: req = urllib.request.Request(url)n ...: res = urllib.request.urlopen(req).read().decode(utf-8)n ...: #解析網頁n ...: soup = BeautifulSoup(res, html.parser)n ...: #循環的方式讀取所需欄位n ...: for content in soup.select(.info):n ...: title = content.select(.title)[0].textn ...: if content.select(.author-item) == []:n ...: anthor = Nonen ...: else:n ...: author = content.select(.author-item)[0].textn ...: price = content.select(.price-tag)[0].textn ...: category = content.select(.category)[0].text[3:]n ...: if content.select(.rating-average)==[]:n ...: rating = Nonen ...: else:n ...: rating = content.select(.rating-average)[0].textn ...: if content.select(.ratings-link) == []:n ...: eveluate_nums = Nonen ...: else:n ...: eveluate_nums = content.select(.ratings-link)[0].text[:-3]n ...: if content.select(.article-desc-brief) == []:n ...: desc = Nonen ...: else:n ...: desc = content.select(.article-desc-brief)[0].textn ...: n ...: print(title,author,price,category,rating,eveluate_nums,desc)n

OK,到目前為止,大功已完成90%。哎?發現上圖中的第二段for循環與這個不一樣啊!為什麼第二段循環里多出來這麼對if...else的結構啊?

好,這個問題問的非常有水平,這是因為有些書沒有人評價,或者有人評價但沒有評分。對於這樣的問題,如果沒有if...else就會報錯,最終導致你的程序無法搜集到所需的數據,不信,你試試~

最後,我們得將爬取出來的數據導入到我們的資料庫。前往記得,在導入資料庫之前,需要在MySQL中建立好一張存數據的表:

接下來使用pymysql模塊將數據導入到資料庫中(關於該模塊的使用,可以參考利用Python讀取外部數據文件),具體腳本如下(如果您操作的話,千萬記得下面的代碼是緊跟著print語句後面的,跟print語句齊平):

In [16]: connect = pymysql.connect(n ...: host = localhost,n ...: user = root,n ...: password = snake,n ...: port = 3306,n ...: database = test,n ...: charset = utf8)n ...: sql = insert into `books`(`title`,`author`,`price`,n ...: `category`,`rating`,`eveluate_nums`,`describtion`) n ...: values (%s,%s,%s,%s,%s,%s,%s)n ...:n ...: try:n ...: with connect.cursor() as cursor:n ...: cursor.execute(sql,(title,author,price,n ...: category,rating,eveluate_nums,desc))n ...: connect.commit()n ...: cursor.close()n ...: finally:n ...: connect.close()n

效果上圖:

OK,如果你也按照上面的操作的話,我想你的結果應該是跟我的一樣。看,這樣一個簡單的爬蟲工作就讓你實現了,是不是有點小興奮。關於爬虫部分,還有很多需要深入學習和了解的,有興趣的朋友可以互相交流,一起往更深的爬蟲黑洞進軍!

最後,再跟大家致歉,原本這期計劃寫《運用R語言的caret包進行特徵選擇》,但由於理論部分實在太難,需要一段時間消化,所以將爬蟲提前推送出來。期待朋友們繼續關注即將推送的《運用R語言的caret包進行特徵選擇》一期內容。

學習與分享,取長補短,歡迎關注博客:每天進步一點點2015

-------------------------------------------------------------這是分隔線------------------------------------------

作者:劉順祥

博客專欄:每天進步一點點2015

微信公眾號:每天進步一點點2015

大家也可以加小編微信:tszhihu (備註:Python),拉大家到 Python愛好者社區 微信群,可以跟各位老師互相交流。謝謝。

也可以關注微信公眾號:Python愛好者社區 (ID:python_shequ)


推薦閱讀:

昨天看球時,球迷都說了啥——彈幕抓取與分析
ELEMENTARY.06.Best Stock
黃哥說很多人的循環都寫不好, 請看。

TAG:Python | 爬虫计算机网络 | Python入门 |