爬蟲代碼改進(二)|多頁抓取與二級頁面
本文是下面兩篇文章的續篇
爬蟲基本原理
爬蟲代碼改進(一)
本系列包括如下內容
- 抓取豆瓣top250一頁多個欄位
- 整合成列表
- 存儲為json文件
- 定義成函數形式
- 多頁抓取之構造url
- 多頁抓取之翻頁
- 抓取二級頁面數據
- 通過生成器優化代碼
- 改寫為類的形式
本文主要講
- 多頁抓取之構造url
- 多頁抓取之翻頁
- 抓取二級頁面數據
上一篇文章我們定義函數,抓取豆瓣top250一頁的數據,代碼如下
import requests # 導入網頁請求庫from bs4 import BeautifulSoup # 導入網頁解析庫import jsondef start_requests(url): r = requests.get(url) return r.contentdef parse(text): soup = BeautifulSoup(text, html.parser) movie_list = soup.find_all(div, class_ = item) result_list = [] for movie in movie_list: mydict = {} mydict[title] = movie.find(span, class_ = title).text mydict[score] = movie.find(span, class_ = rating_num).text mydict[quote] = movie.find(span, class_ = inq).text star = movie.find(div, class_ = star) mydict[comment_num] = star.find_all(span)[-1].text[:-3] result_list.append(mydict) return result_listdef write_json(result): s = json.dumps(result, indent = 4, ensure_ascii=False) with open(movies.json, w, encoding = utf-8) as f: f.write(s)def main(): url = https://movie.douban.com/top250 text = start_requests(url) result = parse(text) write_json(result)if __name__ == __main__: main()
接下來我們要根據這個代碼進行改進。
多頁抓取之構造url
上一篇文章我們已經完善了抓取一個頁面的爬蟲代碼,現在我們需要抓取10個頁面250個電影的信息,抓取多頁信息一般有兩種方式,一種是構造url,一種是翻頁,本節我們來講如何構造url。
我們可以直接看這幾頁的鏈接有什麼規律
第一頁 https://movie.douban.com/top250第二頁 https://movie.douban.com/top250?start=25&filter=第三頁 https://movie.douban.com/top250?start=50&filter=第四頁 https://movie.douban.com/top250?start=75&filter=
可以發現除了第一頁,後面都只換了一個數字,而且是等差數列。那麼我們可以猜想第一頁這樣可不可以
https://movie.douban.com/top250?start=0&filter=
將這個鏈接輸入瀏覽器發現其實就是第一頁,所以我們就可以根據這個規律構造url字元串了,抓取250個電影只需要一個循環。我們現在還是只抓取標題列印出來
import requests # 導入網頁請求庫from bs4 import BeautifulSoup # 導入網頁解析庫def start_requests(url): r = requests.get(url) return r.contentdef parse(text): soup = BeautifulSoup(text, html.parser) movie_list = soup.find_all(div, class_ = item) for movie in movie_list: print(movie.find(span, class_ = title).text)def main(): for i in range(10): url = https://movie.douban.com/top250?start={}&filter=.format(i * 25) text = start_requests(url) parse(text)if __name__ == __main__: main()
接下來,我們需要抓取多個欄位,存儲到json文件中,這時,我們就要把多頁的電影信息放在一個list里,再保存為文件。(注意代碼中的注釋)
import requests # 導入網頁請求庫from bs4 import BeautifulSoup # 導入網頁解析庫import jsondef start_requests(url): r = requests.get(url) return r.contentdef parse(text): soup = BeautifulSoup(text, html.parser) movie_list = soup.find_all(div, class_ = item) for movie in movie_list: mydict = {} mydict[title] = movie.find(span, class_ = title).text mydict[score] = movie.find(span, class_ = rating_num).text quote = movie.find(span, class_ = inq) mydict[quote] = quote.text if quote else None # 抓取10頁就總會遇到這種特殊情況要處理 star = movie.find(div, class_ = star) mydict[comment_num] = star.find_all(span)[-1].text[:-3] result_list.append(mydict) # 向全局變數result_list中加入元素def write_json(result): s = json.dumps(result, indent = 4, ensure_ascii=False) with open(movies.json, w, encoding = utf-8) as f: f.write(s)def main(): for i in range(10): url = https://movie.douban.com/top250?start={}&filter=.format(i * 25) text = start_requests(url) parse(text) write_json(result_list) # 所有電影都存進去之後一起輸出到文件if __name__ == __main__: # 初始化,注意不要在main()函數里定義,因為那裡不是全局變數,其他函數無法調用 result_list = [] main()
多頁抓取之翻頁
翻頁原理是爬取一頁的信息的同時,把下一頁的url也爬取到,再對抓取到的這個url進行爬取。這種方法適用於有「下一頁」標籤的網站,而且一般是網頁url無法構造的時候才用這種方法。
用這種方法要注意對有無下一頁進行判斷
import requests # 導入網頁請求庫from bs4 import BeautifulSoup # 導入網頁解析庫import jsondef start_requests(url): r = requests.get(url) return r.contentdef parse(text): soup = BeautifulSoup(text, html.parser) movie_list = soup.find_all(div, class_ = item) for movie in movie_list: mydict = {} mydict[title] = movie.find(span, class_ = title).text mydict[score] = movie.find(span, class_ = rating_num).text quote = movie.find(span, class_ = inq) mydict[quote] = quote.text if quote else None # 抓取10頁就總會遇到這種特殊情況要處理 star = movie.find(div, class_ = star) mydict[comment_num] = star.find_all(span)[-1].text[:-3] result_list.append(mydict) # 向全局變數result_list中加入元素 nextpage = soup.find(span, class_ = next).a # 找到「下一頁」位置 if nextpage:# 找到的就再解析,沒找到說明是最後一頁,遞歸函數parse就運行結束 nexturl = baseurl + nextpage[href] text = start_requests(nexturl) # 多次使用這個函數,可以看出定義函數的好處,當請求更複雜的時候好處更明顯 parse(text)def write_json(result): s = json.dumps(result, indent = 4, ensure_ascii=False) with open(movies.json, w, encoding = utf-8) as f: f.write(s)def main(): text = start_requests(baseurl) parse(text) write_json(result_list) # 所有電影都存進去之後一起輸出到文件if __name__ == __main__: baseurl = https://movie.douban.com/top250 result_list = [] main()
抓取二級頁面數據
我們通常稱這種列表形式的頁面為一級頁面,而這種每個對象單獨的頁面為二級頁面。前面文章我們只是從一級頁面中提取信息,但是一級頁面展示的信息畢竟有限,因此我們有時候需要進入每個對象自己的頁面去抓取更多信息。
下面我們抓取2頁(50)個電影的詳情頁,因為2頁和10頁代碼上沒什麼差異,而10頁的話就要訪問網站兩百多次,可能爬蟲會被封掉,這個問題不屬於本文的研究範圍,因此我們先避過,只爬兩頁。
我們抓取標題、上映時間、電影時長三個指標。
代碼邏輯是,抓取每個電影的鏈接,再對每個鏈接進行請求,解析每個電影詳情頁獲取數據
代碼如下
import requests # 導入網頁請求庫from bs4 import BeautifulSoup # 導入網頁解析庫import json# 發起請求def start_requests(url): print(url) # 用這條命令知道當前在抓取哪個鏈接,如果發生錯誤便於調試 r = requests.get(url) return r.content# 解析一級網頁,獲取url列表def get_page(text): soup = BeautifulSoup(text, html.parser) movies = soup.find_all(div, class_ = info) pages = [] for movie in movies: url = movie.find(div, class_ = hd).a[href] pages.append(url) return pages# 解析二級網頁,獲取信息def parse_page(text): soup = BeautifulSoup(text, html.parser) mydict = {} mydict[title] = soup.find(span, property = v:itemreviewed).text mydict[duration] = soup.find(span, property = v:runtime).text mydict[time] = soup.find(span, property = v:initialReleaseDate).text return mydict# 將數據讀取到json文件中def write_json(result): s = json.dumps(result, indent = 4, ensure_ascii=False) with open(movies.json, w, encoding = utf-8) as f: f.write(s)def main(): for i in range(7, 9): url = https://movie.douban.com/top250?start={}&filter=.format(i * 25) text = start_requests(url) pageurls = get_page(text) # 解析一級頁面 for pageurl in pageurls: # 解析二級頁面 page = start_requests(pageurl) mydict = parse_page(page) result_list.append(mydict) write_json(result_list) # 所有電影都存進去之後一起輸出到文件if __name__ == __main__: result_list = [] main()
上面代碼經常定義一些全局變數,感覺代碼設計上會有一些不優雅,下一篇文章通過定義生成器和類來解決這種問題
專欄信息
專欄主頁:python編程
專欄目錄:目錄
爬蟲目錄:爬蟲系列目錄
版本說明:軟體及包版本說明
推薦閱讀: