Python爬蟲入門教程:爬取豆瓣小說文學
本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯絡我們以作處理
以下文章來源於騰訊雲 作者:python學習教程
( 想要學習Python?Python學習交流群:1039649593,滿足你的需求,資料都已經上傳群檔案流,可以自行下載!還有海量最新2020python學習資料。 )
前言
Python現在非常火,語法簡單而且功能強大,很多同學都想學Python!所以小的給各位看官們準備了高價值Python學習視訊教程及相關電子版書籍,歡迎前來領取!
今天我就來找一個簡單的網頁進行爬取,就當是給之前的兵書做一個實踐。不然不就是紙上談兵的趙括了嗎。
好了,我們這次的目標是豆瓣圖書Top250,地址是:https://book.douban.com/top250?start=0
準備
爬一個網頁我們至少要知道自己需要什麼資訊,大家看截圖:
紅色箭頭標記的地方就是我們要獲取的資訊了,包括書的名字,作者和出版社資訊,豆瓣評分和一句話簡介。我們有了目標資訊,就需要找到資訊所在的頁面原始碼,然後通過解析原始碼來獲取到資訊資料。那麼,我們怎樣獲得頁面 HTML 原始碼呢?翻閱兵書,我們知道可以使用requests之計。程式碼實現如下:
import requests resp = requests.get('https://book.douban.com/top250?start=0')print(resp.text)
執行程式,我們就輕鬆的獲得了敵軍的 HTML 資訊了。但是問題又來了,我們得到 HTML 資訊後,怎樣得到我們的目標資料呢?
深夜了,一輪彎月躲在雲朵後面,窗外下著雨,我們坐在燭火前,翻閱兵書,頓時茅塞頓開,BeautifulSoup大法好。
我們開啟瀏覽器,按f12到開發者工具,我們從網頁原始碼裡查詢到資料位置,截圖如下:
可以看到書名資訊包含在class=‘pl2’ div裡面的a標籤內,是a標籤的title屬性。發現目標位置後,就簡單多了。我們利用BeautifulSoup來獲得一個物件,按找標準的縮排顯示的html程式碼:
from bs4 import BeautifulSoup soup = BeautifulSoup(resp.text, 'lxml')
推薦大家使用lxml解析器,因為他快。
開始工作
現在我們要用到BeautifulSoup的find_all()選擇器,因為我們這一頁有很多書,而每一本書的資訊都包含在class=pl2的div標籤內,我們使用find_all()就可以直接得到本頁所有書的書名了。我們用find()方法和find_all()方法來做一個比較:
# find_all()方法,# 注意class是Python關鍵詞,後面要加下劃線_:alldiv = soup.find_all('div', class_='pl2')for a in alldiv: names = a.find('a')['title'] print('find_all():', names)# find()方法:alldiv2 = soup.find('div', class_='pl2')names2 = alldiv2.find('a')['title']print('find():', names2 )
執行結果:
find_all(): 追風箏的人find_all(): 小王子# ...# ...省略部分# ...find_all(): 三體Ⅲfind(): 追風箏的人 Process finished with exit code 0
我們通過結果就可以看到兩者之間的差距了,前者輸出了一頁的資料,而後者只輸出了第一條資料。所以包括後面的資訊,由於每一天資料所在標籤是一樣的,我們都是用find_all()方法。
上面的程式碼寫的優雅點,就是這樣實現,注意結果是一個 list:
# 書名, 注意是L小寫,不是阿拉伯數字1alldiv = soup.find_all('div', class_='pl2')names = [a.find('a')['title'] for a in alldiv]print(names)
這樣書名資料我們就得到了,接下來是作者資訊。方法和獲取書名方法一樣:
# 作者,由於資訊在一個p標籤內部,# 我們獲取到標籤直接get_text()方法獲得文字內容allp = soup.find_all('p', class_='pl')authors = [p.get_text() for p in allp]
執行結果:
['[美] 卡勒德·胡賽尼 / 李繼巨集 / 上海人民出版社 / 2006-5 / 29.00元', '[法] 聖埃克蘇佩裡 / 馬振聘 / 人民文學出版社 / 2003-8 / 22.00元', '錢鍾書 / 人民文學出版社 / 1991-2 / 19.00', '餘華 / 南海出版公司 / 1998-5 / 12.00元', # ...# ...省略部分結果# ...'高銘 / 武漢大學出版社 / 2010-2 / 29.80元', '劉慈欣 / 重慶出版社 / 2010-11 / 38.00元']
後面的評分內容和簡介內容也是一樣獲得,只是標籤不同,但是方法一樣,具體也不需要多餘贅述。直接看實現程式碼:
# 評分starspan = soup.find_all('span', class_='rating_nums')scores = [s.get_text() for s in starspan]# 簡介sumspan = soup.find_all('span', class_='inq')sums = [i.get_text() for i in sumspan]
程式執行成功,我們就獲得了4個list,分別是書名,作者,評分和簡介內容。我們要把他們放在一起,打印出來,就是一頁的資料資訊了。
這裡我們使用zip()函式,zip()函式在運算時,會以一個或多個序列做為引數,返回一個元組的列表。同時將這些序列中並排的元素配對。
for name, author, score, sum in zip(names, authors, scores, sums): name = '書名:' + str(name) + '\n' author = '作者:' + str(author) + '\n' score = '評分:' + str(score) + '\n' sum = '簡介:' + str(sum) + '\n' data = name + author + score + sum
我們使用換行符’\n‘給資料資訊一點整齊的樣式。我們可以檢視到列印的結果,並沒有所有資料黏在一起,顯得醜陋。
獲得資訊後,就是儲存資料了。儲存資料也很簡單,Python的檔案讀寫操作就可以實現。程式碼如下:
# 檔名filename = '豆瓣圖書Top250.txt'# 儲存檔案操作with open(filename, 'w', encoding='utf-8') as f: # 儲存資料 f.writelines(data + '=======================' + '\n')print('儲存成功')
執行成功,我們就可以看到專案檔案下面的 txt 檔案了,上面儲存了我們上面打印出來的內容。
書名:追風箏的人作者:[美] 卡勒德·胡賽尼 / 李繼巨集 / 上海人民出版社 / 2006-5 / 29.00元評分:8.8簡介:為你,千千萬萬遍==================# ...# ...書名:活著作者:餘華 / 南海出版公司 / 1998-5 / 12.00元評分:9.1簡介:活著本身就是人生最大的意義==================
但是,我們要的是 250 條資料,而不是一頁的十幾條資料,那麼要怎麼獲得到所有的資料呢。我們可以檢查頁面的資訊,可以看到頁面一共 10 頁,第一頁的URL是https://book.douban.com/top250?start=0。而最後一頁的 URL 是https://book.douban.com/top250?start=225
我們接著多看幾頁,第二頁是https://book.douban.com/top250?start=25,第三頁是https://book.douban.com/top250?start=50。
規律已經很清晰了,我們的頁面的頁數資訊是最後的start=後面的數字。而且數字從0開始到225,每一頁數字加 25.這就很簡單了,我們以https://book.douban.com/top250?start=為基層URL,每一頁在後面加頁面的頁數數字。就可以得到所有的頁面 url 了。再以for迴圈迭代每一個 url,使用上面獲取資料的方法,獲得所有的資料資訊。
獲取所有頁面URL的程式碼如下:
base_url = 'https://book.douban.com/top250?start='urllist = []# 從0到225,間隔25的陣列for page in range(0, 250, 25): allurl = base_url + str(page) urllist.append(allurl)
我們把他儲存在 list 裡面,好用迴圈迭代。
程式碼
那麼,所有的功能都實現了。現在,我們只要將所有的程式碼組合起來,就可以實現我們需要的所有功能了。
上程式碼:
# -*- coding:utf-8 -*-# author: yukunimport requestsfrom bs4 import BeautifulSoup # 發出請求獲得HTML原始碼的函式def get_html(url): # 偽裝成瀏覽器訪問 headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'} resp = requests.get(url, headers=headers).text return resp # 解析頁面,獲得資料資訊def html_parse(): # 呼叫函式,for迴圈迭代出所有頁面 for url in all_page(): # BeautifulSoup的解析 soup = BeautifulSoup(get_html(url), 'lxml') # 書名 alldiv = soup.find_all('div', class_='pl2') names = [a.find('a')['title'] for a in alldiv] # 作者 allp = soup.find_all('p', class_='pl') authors = [p.get_text() for p in allp] # 評分 starspan = soup.find_all('span', class_='rating_nums') scores = [s.get_text() for s in starspan] # 簡介 sumspan = soup.find_all('span', class_='inq') sums = [i.get_text() for i in sumspan] for name, author, score, sum in zip(names, authors, scores, sums): name = '書名:' + str(name) + '\n' author = '作者:' + str(author) + '\n' score = '評分:' + str(score) + '\n' sum = '簡介:' + str(sum) + '\n' data = name + author + score + sum # 儲存資料 f.writelines(data + '=======================' + '\n') # 獲得所有頁面的函式def all_page(): base_url = 'https://book.douban.com/top250?start=' urllist = [] # 從0到225,間隔25的陣列 for page in range(0, 250, 25): allurl = base_url + str(page) urllist.append(allurl) return urllist # 檔名filename = '豆瓣圖書Top250.txt'# 儲存檔案操作f = open(filename, 'w', encoding='utf-8')# 呼叫函式html_parse()f.close()print('儲存成功。')
我們只用了36行的程式碼(去掉空行和註釋)就實現了抓取豆瓣圖書的資料了。大家是不是覺得很簡單了,不要興奮,這只是一個小白最基礎的練手專案,大家快去找更有挑戰性的專案實現吧。大家加油。