在前面幾篇文章中,我們了解了Python爬蟲技術(shù)的三個基礎(chǔ)環(huán)節(jié):下載網(wǎng)頁、提取數(shù)據(jù)以及保存數(shù)據(jù)。
這一篇文章,我們通過實際操作來將三個環(huán)節(jié)串聯(lián)起來,以國產(chǎn)電視劇為例,構(gòu)建我們的電視劇評分?jǐn)?shù)據(jù)集。
1、需求描述
收集目前國產(chǎn)電視劇的相關(guān)數(shù)據(jù),需要構(gòu)建國產(chǎn)電視劇和評分的數(shù)據(jù)集。
2、需求說明
收集國產(chǎn)電視劇的數(shù)據(jù),越全越好,至少收集評分、電視劇名稱、主演信息三個信息。之后將數(shù)據(jù)存儲在一個 csv 表中,表頭如下:
- title,代表電視劇名稱
- rating,代表電視劇評分
- stars,代表電視劇主演
3、初步分析
在基于 Python 技術(shù)來構(gòu)建數(shù)據(jù)集的方式中,首當(dāng)其沖要做的事情就是選擇要抓取的網(wǎng)站。選擇的標(biāo)準(zhǔn)一般主要看網(wǎng)站是否具備我們想要的信息,以及是否方便抓取。
這次我們要抓取的電視劇信息中,還有一個重要的考量因素就是是否方便抓取多個頁面,畢竟一個網(wǎng)頁一般都無法包含全部的電視劇信息。
我們在下載 HTML 頁面的環(huán)節(jié)往往需要下載多個頁才能獲取完整的數(shù)據(jù)。
通過在搜索引擎搜索有電視劇列表的網(wǎng)站,我們決定下載“全集網(wǎng)”中的電視劇信息。
4、全集網(wǎng)主頁分析
打開全集網(wǎng)中的國產(chǎn)電視劇主頁,可以看到如下圖示。
通過觀察以上頁面,可以發(fā)現(xiàn)該網(wǎng)頁我們想要的字段:標(biāo)題、評分和主演信息在頁面上都有顯示,只要顯示就說明我們可以通過爬蟲拿到。
同時注意我們地址欄url地址的變化,當(dāng)前是:
現(xiàn)在我們來考察它的加載方式,拉到底部,可以看到該網(wǎng)頁提供的是傳統(tǒng)的翻頁操作。如下所示:
我們點擊第二頁,發(fā)現(xiàn)跳轉(zhuǎn)到了一個新的頁面,該頁面的 URL 和我們一開始訪問的差不多,只是其中有一個數(shù)據(jù)的值變成了2。
這說明我們可以通過不斷改變 URL 中的 頁碼 參數(shù)的值,來訪問第二頁之后的內(nèi)容。這樣在后續(xù)寫代碼中,我們只需要寫針對一個頁面的抓取代碼,然后用一個循環(huán)來不斷執(zhí)行該方法,并每次疊加 page 的值就能實現(xiàn)將所有電視劇的內(nèi)容抓取下來。
綜上所述,全集網(wǎng)的頁面更符合我們本次抓取的任務(wù)需求,我們后續(xù)就將該網(wǎng)頁作為我們的抓取目標(biāo)。
5、數(shù)據(jù)獲取-下載所需網(wǎng)頁
全集網(wǎng)的電視劇比較多,我們本次下載的html網(wǎng)頁也會很多,所以可以在電腦上新建一個文件夾,在文件夾中新建我們的程序文件,將下載的網(wǎng)頁保存在同級文件夾即可。(創(chuàng)建文件夾可以手動創(chuàng)建,無需通過程序,大家自行創(chuàng)建吧!)
創(chuàng)建完文件夾和程序文件后,先編寫下載網(wǎng)頁和保存文件的代碼。
不想寫的可以直接把前面文章中的網(wǎng)頁下載代碼和數(shù)據(jù)保存到文件的代碼復(fù)制過來。
import urllib3
# 第一個函數(shù),用來下載網(wǎng)頁,返回網(wǎng)頁內(nèi)容
# 參數(shù) url 代表所要下載的網(wǎng)頁網(wǎng)址。
def download_content(url):
http = urllib3.PoolManager()
response = http.request("GET", url)
response_data = response.data
html_content = response_data.decode()
return html_content
# 第二個函數(shù),將字符串內(nèi)容保存到文件中
# 第一個參數(shù)為所要保存的文件名,第二個參數(shù)為要保存的字符串內(nèi)容的變量
def save_to_file(filename, content):
fo = open(filename,"w", encoding="utf-8")
fo.write(content)
fo.close()
運行以上代碼后,我們就可以使用這兩個函數(shù)來下載網(wǎng)頁了。
(1)單個網(wǎng)頁下載
先來下載一個網(wǎng)頁試試情況:
#?將我們找到的電視劇網(wǎng)的網(wǎng)址存儲在變量?url?中
url = "https://www.fschurun.com/vodshow/13--------1---.html"
#?將url?對應(yīng)的網(wǎng)頁下載下來,并把內(nèi)容存儲在?html_content?變量中
html_content = download_content(url)
#?將?html_content?變量中的內(nèi)容存儲在?htmls?文件夾中,文件名為?tv1.html?代表第一頁
save_to_file("tvs_html/tv1.html",html_content)
接下來,我們點擊 tv1.html 打開,來查看是否有我們需要的電視劇信息?;剡^頭去看我們上文中發(fā)的截圖,有個電視劇的名稱是《藏藥令》。
說明電視劇網(wǎng)的內(nèi)容不是動態(tài)生成的,可以用 urllib3 進(jìn)行下載。
(2)多個網(wǎng)頁下載
現(xiàn)在第一個網(wǎng)頁已經(jīng)下載成功了。我們目標(biāo)是下載 137個網(wǎng)頁的內(nèi)容,所以剩余的可以通過一個循環(huán)來下載。在我們之前的分析中,下載第二頁和之后的內(nèi)容只需要修改 URL 中的 page 的值即可。
另外,在我們通過循環(huán)來批量下載內(nèi)容的時候,還有一個很重要的注意事項,一般都會在每次下載之后等待幾百毫秒的時間,再進(jìn)行下一次下載,這樣可以避免短時間內(nèi)對網(wǎng)站發(fā)起大量的下載請求,浪費網(wǎng)站的帶寬資源。
在今天這個案例中,我們每次下載之后等待一秒再進(jìn)行下一次下載。在 Python 中,我們可以通過 time 模塊的 sleep 方法來使程序暫停固定的時間。
代碼如下:
import time
for i in range(2, 137):
url = "https://www.fschurun.com/vodshow/13--------"+str(i)+"---.html";
print("begin download:",url);
html = download_content(url);
filename = "tvs_html/tv"+str(i)+".html";
save_to_file(filename, html);
print("download end ");
time.sleep(1);
執(zhí)行上述程序,可以看到程序每隔一秒鐘輸出一行信息,如下所示。
執(zhí)行完畢后,我們在側(cè)邊欄打開 htmls 文件夾,可以看到我們的 137 個 html 文件已經(jīng)保存成功。
6、數(shù)據(jù)提取
我們前面的需求分析已經(jīng)提到了,需要電視劇的名稱、評分和主演信息。那我們就開始分析網(wǎng)頁,找到我們需要的數(shù)據(jù)所在的標(biāo)簽。
從圖中我們可以得出:
- 電視劇列表是用ul布局,每個li代表一個電視劇。
- 在li里面,又有兩個div,第一個div來展示電視劇評分。第二個div來展示電視劇名稱和主演信息。
- 具體的內(nèi)容又以span標(biāo)簽、h4標(biāo)簽或p標(biāo)簽來展示。
至此,我們的數(shù)據(jù)提取思路基本就清晰了:
- 獲取所有 class=ewave-vodlist__box 的 div 標(biāo)簽對象。
- 針對每一個標(biāo)簽對象,都嘗試:
- 查找div,class為ewave-vodlist__thumb lazyload下面的span標(biāo)簽的值,作為評分?jǐn)?shù)據(jù)。
- 查找div,class為ewave-vodlist__detail下面的h4標(biāo)簽的值,作為電視劇名稱。
- 查找div,class為ewave-vodlist__detail下面的p標(biāo)簽的值,作為主演數(shù)據(jù)
(1)提取單個HTML的所有電視劇信息
接下里,我們按照上面的數(shù)據(jù)提取思路,來編寫獲取單個HTML文件電視劇信息的代碼。單個文件處理完之后,擴(kuò)展到多個文件的數(shù)據(jù)處理就簡單了。
代碼如下:
from bs4 import BeautifulSoup
#?輸入?yún)?shù)為要分析的?html?文件名,返回值為對應(yīng)的?BeautifulSoup?對象
def create_doc_from_file(filename):
fo = open(filename, "r", encoding="utf-8");
html_content = fo.read();
fo.close()
doc = BeautifulSoup(html_content);
return doc;
之后根據(jù)初步分析中分析的步驟,實現(xiàn)內(nèi)容的抓取。
# 用tv1.html的內(nèi)容創(chuàng)建BeautifulSoup對象
doc = create_doc_from_file("tvs_html/tv1.html");
# 查找class="ewave-vodlist__box" 的所有 div 標(biāo)簽
# 并以列表形式存儲在 box_list 中
box_list = doc.find_all("div",class_="ewave-vodlist__box");
# 使用遍歷循環(huán)遍歷 box_list 中的所有標(biāo)簽對象
for box in box_list:
# 根據(jù)上述分析的思路,分別獲取包含標(biāo)題、評分、和演員信息的標(biāo)簽
rating = box.find("div",class_ = "ewave-vodlist__thumb lazyload").find("span",class_="pic-tag pic-tag-h").text;
title = box.find("div",class_="ewave-vodlist__detail").find("h4",class_ = "title text-overflow").text;
stars = box.find("div",class_="ewave-vodlist__detail").find("p",class_ = "text text-overflow text-muted hidden-xs text-actor").text;
print(title, rating, stars)
執(zhí)行之后,輸出如下(截取了部分日志)??梢钥吹轿覀兿胍男畔⑹怯辛?,但是卻好像帶了很多沒必要的空格和換行。
針對抽取的結(jié)果出現(xiàn)空格和換行的問題,我們可以使用正則表達(dá)式來處理。
創(chuàng)建一個格式處理的函數(shù):
import re
def remove_extra_spaces(string):
# 將連續(xù)的非空格字符與其前面的空格合并為一個單詞
string = re.sub(' +',' ',string);
# 去除開頭和結(jié)尾的空格、換行
string = string.strip().replace("\n","");
return string;
在我們上面打印語句中,主演的數(shù)據(jù)中調(diào)用一下這個函數(shù),就可以按規(guī)則去掉空格和換行。
# 用tv1.html的內(nèi)容創(chuàng)建BeautifulSoup對象
doc = create_doc_from_file("tvs_html/tv1.html");
# 查找class="ewave-vodlist__box" 的所有 div 標(biāo)簽
# 并以列表形式存儲在 box_list 中
box_list = doc.find_all("div",class_="ewave-vodlist__box");
# 使用遍歷循環(huán)遍歷 box_list 中的所有標(biāo)簽對象
for box in box_list:
# 根據(jù)上述分析的思路,分別獲取包含標(biāo)題、評分、和演員信息的標(biāo)簽
rating = box.find("div",class_ = "ewave-vodlist__thumb lazyload").find("span",class_="pic-tag pic-tag-h").text;
title = box.find("div",class_="ewave-vodlist__detail").find("h4",class_ = "title text-overflow").text;
stars = box.find("div",class_="ewave-vodlist__detail").find("p",class_ = "text text-overflow text-muted hidden-xs text-actor").text;
print(title, rating, remove_extra_spaces(stars))
這回打印出來的數(shù)據(jù)格式就清爽很多了:
(2)提取多個HTML的內(nèi)容
通過上述代碼,我們已經(jīng)可以將 tv1.html 文件中的所有電視劇信息給打印出來。但我們這次一共有一百多個 html 文件,要怎么實現(xiàn)處理多個 html 文件呢?
因為這一百個 HTML 文件雖然電視劇內(nèi)容不一樣,但是標(biāo)簽結(jié)構(gòu)卻是基本一樣的(在電視劇網(wǎng)翻頁的時候,可以看到每一頁的樣子都是一樣的)。所以我們只需要將上面的代碼放在循環(huán)中循環(huán)運行,然后每次循環(huán)都處理不同的 html 文件即可。
為了讓代碼更加清晰,我們先將上面的處理單個文件的代碼改寫為函數(shù),參數(shù)就是要處理的 html 文件名,函數(shù)則命名為:get_tv_from_html。
# 從參數(shù)指定的 html 文件中獲取電視劇的相關(guān)信息
def get_tv_from_html(html_file_name):
doc = create_doc_from_file(html_file_name);
box_list = doc.find_all("div",class_="ewave-vodlist__box");
for box in box_list:
rating = box.find("div",class_ = "ewave-vodlist__thumb lazyload").find("span",class_="pic-tag pic-tag-h").text;
title = box.find("div",class_="ewave-vodlist__detail").find("h4",class_ = "title text-overflow").text;
stars = box.find("div",class_="ewave-vodlist__detail").find("p",class_ = "text text-overflow text-muted hidden-xs text-actor").text;
# 將獲取的三個變量打印出來,看看是否正確。
print(title, rating, remove_extra_spaces(stars))
# 試試用新寫的函數(shù)處理一 tv2.html
get_tv_from_html("tvs_html/tv2.html")
調(diào)用后輸出如下:
可以看到,我們成功用我們寫的函數(shù)來從 tv2.html 中提取了電視劇的信息。這樣要實現(xiàn)從一百多個文件中抽取信息,只需要寫一個循環(huán),來每次傳給 get_tv_from_html 函數(shù)不同的文件名即可?!具@里就不再放循環(huán)代碼了,新手小伙伴可以試試自己來寫,如果有問題可以聯(lián)系?!?/p>
截止到現(xiàn)在,我們已經(jīng)把網(wǎng)頁下載下來了,并且把我們需要的內(nèi)容抽取出來了,剩下的一步就是寫到CSV中。
7、數(shù)據(jù)保存-將數(shù)據(jù)保存到CSV中
要將數(shù)據(jù)保存為 csv 的記錄,我們首先需要將每一行數(shù)據(jù)保存為字典,然后以一個字典列表的形式傳遞給 csv 模塊的 DictWriter。
(1)準(zhǔn)備保存到CSV的函數(shù)
為了讓后續(xù)代碼更簡潔,我們先將把字典列表保存到 csv 文件的操作寫成一個函數(shù)。
# 導(dǎo)入 csv 模塊
import csv
# 輸入有三個參數(shù):要保存的字典列表,csv 文件名,和表頭
def write_dict_list_to_file(dict_list, filename, headers):
# 當(dāng)要處理的網(wǎng)頁比較復(fù)雜時,增加 encoding 參數(shù)可以兼容部分特殊符號
fo = open(filename, "w", newline="", encoding="utf-8")
writer = csv.DictWriter(fo, headers);
writer.writeheader();
writer.writerows(dict_list)
fo.close()
(2)創(chuàng)建電視劇字典列表
all_tv_dict = []
(3)改造 get_tv_from_html 函數(shù)
# 從參數(shù)指定的 html 文件中獲取電視劇的相關(guān)信息
def get_tv_from_html(html_file_name):
doc = create_doc_from_file(html_file_name);
#【新增】當(dāng)前處理的文件的字典列表
tv_list = [];
box_list = doc.find_all("div",class_="ewave-vodlist__box");
for box in box_list:
rating = box.find("div",class_ = "ewave-vodlist__thumb lazyload").find("span",class_="pic-tag pic-tag-h").text;
title = box.find("div",class_="ewave-vodlist__detail").find("h4",class_ = "title text-overflow").text;
stars = box.find("div",class_="ewave-vodlist__detail").find("p",class_ = "text text-overflow text-muted hidden-xs text-actor").text;
#【新增】使用字典來保存上面抽取的數(shù)據(jù),字典的key和csv的表頭保持一致
tv_dict = {}
tv_dict['title'] = title;
tv_dict['rating'] = rating;
tv_dict['stars'] = stars;
tv_list.append(tv_dict)
return tv_list
#【新增】調(diào)用修改后的程序
tv_list = get_tv_from_html("tvs_html/tv2.html")
print(tv_list)
運行后結(jié)果如下:
(4)獲取所有文件的電視劇信息
目前,我們通過 get_tv_from_file 函數(shù),已經(jīng)可以獲取單個 html 的電視劇列表,現(xiàn)在我們需要通過一個循環(huán),去處理所有的 html。對于每一個 html 文件,獲取字典列表之后,都把列表添加到我們的總列表:all_tv_dict 中。這樣,在循環(huán)執(zhí)行結(jié)束后,all_tv_dict 變量中就包含了所有電視劇的信息。
# 因為是處理 tv1- tv136 的文件,所以i 循環(huán)從1到136
for i in range(1, 136):
# 拼出每一次要處理的文件名
filename = "tvs_html/tv"+str(i)+".html";
# 調(diào)用 get_tv_from_html 處理當(dāng)次循環(huán)的文件
# 將這個文件中的電視劇列表存儲在 dict_list 變量
dict_list = get_tv_from_html(filename);
# 將 dict_list 的內(nèi)容添加到總列表 all_tv_dict 中
# 列表的拼接可以直接使用 + 號
all_tv_dict = all_tv_dict + dict_list
# 打印出總列表的長度,看看我們一共抓取到了幾部電視劇
print(len(all_tv_dict))
因為要用 BeautifulSoup 處理一百多個文件,這里執(zhí)行會有點慢。需要耐心等一下,執(zhí)行完畢后輸出結(jié)果為 9270。
說明我們一共抓取了9270部電視劇。
(5)保存結(jié)果到 csv 文件中
在需求說明中,已經(jīng)明確了要保存的 csv 文件名為:tv_rating.csv, 表頭為:title, rating, stars。
現(xiàn)在,我們所有電視劇的信息都已經(jīng)存儲在 all_tv_dict 總列表中,現(xiàn)在我們只需要調(diào)用存儲到 csv 的函數(shù)將其保存到 csv 文件即可。
#?調(diào)用之前準(zhǔn)備的?write_dict_list_to_csv?函數(shù)
#?第一個參數(shù)為要保存的列表,這里就是我們存儲了所有電視劇耳朵總列表?all_tv_dict
#?第二個參數(shù)為要保存的文件名
#?第三個參數(shù)為要保存的?csv?文件的表頭
write_dict_list_to_file(all_tv_dict, "tv_rating.csv", ["title", "rating", "stars"]);
執(zhí)行之后,沒有內(nèi)容輸出,但是可以看到在源代碼文件夾下已經(jīng)生成了 tv_rating.csv 文件。
使用 Excel 打開該 csv 文件,可以看到我們的表頭已經(jīng)正確寫入,表頭對應(yīng)的內(nèi)容也已經(jīng)正確寫入。
至此,一份國產(chǎn)電視劇評分的數(shù)據(jù)集就制作完畢了。文章來源:http://www.zghlxwxcb.cn/news/detail-811919.html
更多精彩文章歡迎關(guān)注公眾號:服務(wù)端技術(shù)精選文章來源地址http://www.zghlxwxcb.cn/news/detail-811919.html
到了這里,關(guān)于快樂學(xué)Python,使用爬蟲爬取電視劇信息,構(gòu)建評分?jǐn)?shù)據(jù)集的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!