1. 程式人生 > 實用技巧 >Python爬蟲入門教程:爬取豆瓣小說文學

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行的程式碼(去掉空行和註釋)就實現了抓取豆瓣圖書的資料了。大家是不是覺得很簡單了,不要興奮,這只是一個小白最基礎的練手專案,大家快去找更有挑戰性的專案實現吧。大家加油。