Beautiful Soup 是一個(gè)可以從HTML或XML文件中提取數(shù)據(jù)的Python庫(kù).它能夠通過(guò)你喜歡的轉(zhuǎn)換器實(shí)現(xiàn)慣用的文檔導(dǎo)航,查找,修改文檔的方式.Beautiful Soup會(huì)幫你節(jié)省數(shù)小時(shí)甚至數(shù)天的工作時(shí)間.
這是一個(gè)利器俩檬,讓我們能夠從復(fù)雜的HTML代碼里面萎胰,提取出我們我們想要的目標(biāo)數(shù)據(jù)。
-
本章我們會(huì)以 爬取豆瓣電影成都即將上映的影片信息 作為案例講解 BeautifulSoup 的用法棚辽。
我們需要爬取的內(nèi)容有:
所有影片的 名字技竟、詳情鏈接、上映時(shí)間屈藐、影片類型榔组、地區(qū)、關(guān)注者數(shù)量联逻。
網(wǎng)頁(yè)截圖如下:
開(kāi)始本章前搓扯,請(qǐng)確認(rèn)你已經(jīng)安裝Python以及jupyter、requests包归、lxml和bs4這4個(gè)Python包锨推。如果你沒(méi)有,那請(qǐng)移步前面的章節(jié)進(jìn)行安裝操作:
?
-
打開(kāi)jupyter開(kāi)始寫代碼
命令行輸入jupyter notebook并回車换可。如果你設(shè)置了默認(rèn)瀏覽器退客,那么會(huì)自動(dòng)打開(kāi)瀏覽器進(jìn)去到你打開(kāi)cmd的文件夾轻要。然后點(diǎn)擊右邊的New,Python3响疚,我們就新建了一個(gè)Python3的項(xiàng)目了慨削。
如果你正好看了上一章節(jié)洞渔,那么也可以使用上次的代碼文件,直接打開(kāi)就好了缚态。
-
requests請(qǐng)求到網(wǎng)頁(yè)源代碼
運(yùn)用上一節(jié)學(xué)到的知識(shí)磁椒,我們先進(jìn)行爬取第一步,獲取到網(wǎng)頁(yè)源代碼玫芦。
豆瓣電影即將上映的影片的網(wǎng)頁(yè)的地址是:https://movie.douban.com/cinema/later/chengdu/
那么我們開(kāi)始編寫代碼來(lái)獲取到這個(gè)網(wǎng)頁(yè)的源代碼:
import requests
# 舊版教程
# url = "https://movie.douban.com/cinema/later/chengdu/"
# response = requests.get(url)
# 2019-12-23更新浆熔,解決不能獲取到響應(yīng)的問(wèn)題
url = "https://movie.douban.com/cinema/later/chengdu/" # URL不變
# 新增偽裝成瀏覽器的header
fake_headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'
}
response = requests.get(url, headers=fake_headers) # 請(qǐng)求參數(shù)里面把假的請(qǐng)求header加上
print(response.content.decode('utf-8'))
我們可以成功看到網(wǎng)頁(yè)的源代碼了,證明網(wǎng)頁(yè)下載沒(méi)問(wèn)題桥帆,而且在網(wǎng)頁(yè)代碼之中医增,可以找到我們需要的電影信息(在輸出界面一直往下翻,快到底了就能看到啦~)
-
保存網(wǎng)頁(yè)到本地老虫,方便快速加載
網(wǎng)頁(yè)我們拿到了叶骨,下面就要進(jìn)行每一步的調(diào)試了
為了我們能夠快速調(diào)試自己的代碼、給豆瓣服務(wù)器減少一點(diǎn)壓力祈匙,也為了避免因?yàn)樽约赫{(diào)試過(guò)快忽刽,被豆瓣封掉天揖,所以我們最好把網(wǎng)頁(yè)保存到本地。這樣我們就能用最短的時(shí)間加載到網(wǎng)頁(yè)跪帝,而不用每次調(diào)試都去豆瓣請(qǐng)求一下今膊。
import requests
# 舊版教程
# url = "https://movie.douban.com/cinema/later/chengdu/"
# response = requests.get(url)
# 2019-12-23更新,解決不能獲取到響應(yīng)的問(wèn)題
url = "https://movie.douban.com/cinema/later/chengdu/" # URL不變
# 新增偽裝成瀏覽器的header
fake_headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'
}
response = requests.get(url, headers=fake_headers) # 請(qǐng)求參數(shù)里面把假的請(qǐng)求header加上
# 保存網(wǎng)頁(yè)到本地
file_obj = open('douban.html', 'w') # 以寫模式打開(kāi)名叫 douban.html的文件
# 如果打開(kāi)網(wǎng)頁(yè)顯示的是亂碼那么就用下一行代碼
# file_obj = open('douban.html', 'w', encoding="utf-8") # 以寫模式打開(kāi)名叫 douban.html的文件伞剑,指定編碼為utf-8
file_obj.write(response.content.decode('utf-8')) # 把響應(yīng)的html內(nèi)容
file_obj.close() # 關(guān)閉文件斑唬,結(jié)束寫入
恩,Python保存文件黎泣,就這么簡(jiǎn)單恕刘。。抒倚。
這個(gè)時(shí)候雪营,你打開(kāi)jupyter最開(kāi)始彈出來(lái)的頁(yè)面,可以找到一個(gè)douban.html的文件了衡便,點(diǎn)擊打開(kāi),內(nèi)容和我們目標(biāo)網(wǎng)頁(yè)一模一樣洋访,但是瀏覽器頂端的網(wǎng)址變了镣陕。
-
讀取文件并用BeautifulSoup加載
我們現(xiàn)在暫時(shí)不使用上面的 區(qū)塊(cell) 了,就讓它保留這樣子以便后用姻政;我們?cè)谙旅娴男耤ell呆抑,開(kāi)始鍵入代碼讀取文件并加載到BeautifulSoup里面:
from bs4 import BeautifulSoup # 從bs4引入BeautifulSoup
# 讀取文件內(nèi)容到html變量里面
file_obj = open('douban.html', 'r') # 以讀方式打開(kāi)文件名為douban.html的文件
html = file_obj.read() # 把文件的內(nèi)容全部讀取出來(lái)并賦值給html變量
file_obj.close() # 關(guān)閉文件對(duì)象
soup = BeautifulSoup(html, 'lxml') # 初始化BeautifulSoup
print(soup) # 輸出BeautifulSoup轉(zhuǎn)換后的內(nèi)容
- 這里要說(shuō)明一下,初始化BeautifuSoup的參數(shù)汁展。
第一個(gè)參數(shù)html
是網(wǎng)頁(yè)的源代碼鹊碍,可以是個(gè)Unicode字符串,也可以是一個(gè)二進(jìn)制字符串(如果第一個(gè)參數(shù)是字符串并且網(wǎng)頁(yè)自帶了charset信息食绿,BS會(huì)默認(rèn)采用網(wǎng)頁(yè)的默認(rèn)編碼解碼侈咕,否則默認(rèn)以你當(dāng)前文件執(zhí)行的編碼(通常是utf-8)進(jìn)行解析。如果是二進(jìn)制字符串器紧,如果自己手動(dòng)指定了編碼耀销,就以指定編碼解析,否則默認(rèn)utf-8解析)铲汪。
第二個(gè)參數(shù)lxml
是BeautifulSoup采用的網(wǎng)頁(yè)解析器熊尉,我們安裝lxml用處就在這體現(xiàn)出來(lái)了。如果不指定掌腰,那么默認(rèn)會(huì)采用Python內(nèi)置的html.parser
進(jìn)行解析狰住。
還有更多的可用參數(shù)在之后進(jìn)行講解。
而輸出的內(nèi)容和我們之前的輸出似乎是完全一樣的齿梁,因?yàn)槲覀冞€沒(méi)對(duì)soup進(jìn)行操作催植。
-
BeautifulSoup的基本使用語(yǔ)法規(guī)則
.find()
使用示例
soup.find('a')
。那么會(huì)返回在soup包含的源代碼中,遇到的第一個(gè)<a>...</a>標(biāo)簽內(nèi)容對(duì)象查邢。
soup.find('a', id='next')
蔗崎。那么會(huì)返回在soup包含的源代碼中,遇到的第一個(gè)有屬性為id扰藕,值為next的<a>對(duì)象缓苛,比如<a id="next">...</a>。(不只可以用id邓深,大部分其他的屬性都可以直接使用未桥,比如src、name芥备。 值得注意的是冬耿,class這個(gè)屬性因?yàn)槭荘ython關(guān)鍵字,不能直接使用萌壳,所以在BS里面亦镶,使用class_='...'進(jìn)行代替 )
find
返回的結(jié)果,依然可以繼續(xù)使用find()
或者find_all()
方法袱瓮。如果找不到指定的內(nèi)容缤骨,find會(huì)返回None
。.find_all()
使用示例
soup.find_all('a')
尺借。那么會(huì)返回在soup包含的源代碼中绊起,遇到的所有<a>...</a>標(biāo)簽內(nèi)容的可迭代對(duì)象(我們可以把它看成一個(gè) list 或者數(shù)組)。
soup.find_all('a', class_='next')
燎斩。那么會(huì)返回在soup包含的源代碼中虱歪,遇到的所有屬性為class,值為next的<a>的 可迭代對(duì)象栅表,比如<a class="next">...</a>笋鄙。(語(yǔ)法和find也一樣,class也不能直接寫)
find_all
返回的“l(fā)ist”中的單個(gè)對(duì)象 依然可以繼續(xù)使用find()
或者find_all()
方法谨读。如果找不到指定的內(nèi)容局装,find_all會(huì)返回一個(gè)空的“l(fā)ist”。獲取元素的某個(gè)屬性
soup['src]
劳殖,這樣我們就能取出soup對(duì)象的src屬性了铐尚。如果該屬性不存在,那么程序會(huì)報(bào)錯(cuò)哆姻。獲取元素中的所有文本
soup.text
宣增,假設(shè)soup對(duì)象為<div>你好<a>復(fù)聯(lián)</a></div>
,那么這個(gè)操作返回字符串是你好復(fù)聯(lián)
矛缨。
-
分析網(wǎng)頁(yè)爹脾,制訂提取內(nèi)容策略
這一步非常重要帖旨,直接影響了我們能不能提取到我們想要的內(nèi)容。
我們返回瀏覽器打開(kāi)的豆瓣網(wǎng)頁(yè)灵妨。找到網(wǎng)頁(yè)中的第一個(gè)電影的名字解阅,鼠標(biāo)指向該名字,點(diǎn)擊右鍵泌霍,選擇 檢查/審查元素货抄,然后便會(huì)打開(kāi)一個(gè)新的小窗口在頁(yè)面上,并且將網(wǎng)頁(yè)代碼中電影的名字顯示在了里面朱转,并且你鼠標(biāo)指向的元素會(huì)顯示出它的大小蟹地,內(nèi)容會(huì)被選中。
審查元素
我們同時(shí)滑動(dòng)鼠標(biāo)的位置藤为,應(yīng)該會(huì)發(fā)現(xiàn)
當(dāng)鼠標(biāo)劃到圖片中的<ul>...</ul>
標(biāo)簽的時(shí)候怪与,復(fù)仇者聯(lián)盟影片的詳細(xì)信息被選中了。
當(dāng)鼠標(biāo)劃到下一個(gè)<div class="item mod odd">...</div>
的時(shí)候缅疟,下一個(gè)影片戰(zhàn)犬瑞克斯的所有信息被選中了分别。
當(dāng)鼠標(biāo)劃到圖片上方的<div id="showing-soon" class="tab-bd">
的時(shí)候,整個(gè)我們需要采集的影片信息都被選中了存淫。- 這幾個(gè)動(dòng)作告訴了我們的信息有:
- 我們需要的內(nèi)容全都在
<div id="showing-soon" class="tab-bd"></div>
里面茎杂。 - 每個(gè)影片的信息,都在一個(gè)
<div class="item mod odd">...</div>
或者<div class="item mod">...</div>
里面纫雁。畫面左邊的影片沒(méi)有odd
屬性,右邊的有odd
屬性(這好像對(duì)于我們采集信息沒(méi)啥用)倾哺。
- 我們需要的內(nèi)容全都在
那么我們的策略轧邪,就是先找到囊括了所有的影片的
div
,然后再?gòu)倪@個(gè)div里面找到所有的影片的div
羞海,最后再?gòu)拿總€(gè)影片的div里面解析出來(lái)我們需要的名字忌愚、鏈接等等信息。代碼就可以稍微往下寫一點(diǎn)了却邓。也就開(kāi)始要運(yùn)用前面提到的BS的一些基本用法了: - 這幾個(gè)動(dòng)作告訴了我們的信息有:
from bs4 import BeautifulSoup # 從bs4引入BeautifulSoup
# 讀取文件內(nèi)容到html變量里面
file_obj = open('douban.html', 'r') # 以讀方式打開(kāi)文件名為douban.html的文件
html = file_obj.read() # 把文件的內(nèi)容全部讀取出來(lái)并賦值給html變量
file_obj.close() # 關(guān)閉文件對(duì)象
soup = BeautifulSoup(html, 'lxml') # 初始化BeautifulSoup
# print(soup) # 輸出BeautifulSoup轉(zhuǎn)換后的內(nèi)容
all_movies = soup.find('div', id="showing-soon") # 先找到最大的div
# print(all_movies) # 輸出最大的div的內(nèi)容
for each_movie in all_movies.find_all('div', class_="item"): # 從最大的div里面找到影片的div
print(each_movie) # 輸出每個(gè)影片div的內(nèi)容
-
提取信息
那么這一步我們需要做的硕糊,就是從這個(gè)包含了電影所有信息的div里面,提取出我們需要的信息了腊徙。先截個(gè)圖简十,找到我們的目標(biāo)們。
單個(gè)div視圖現(xiàn)在撬腾,代碼中
each_movie
這個(gè)變量的內(nèi)容就是截圖中的內(nèi)容螟蝙。
目標(biāo)們的位置:
電影屬性 | 文檔中的位置 |
---|---|
名字 | 在第 2 個(gè)<a> 標(biāo)簽里面 |
鏈接 | 在第 1 個(gè)和第 2 個(gè)<a> 標(biāo)簽的 href 屬性 里面 |
上映日期 | 在第 1 個(gè)<li> 標(biāo)簽里面 |
類型 | 在第 2 個(gè)<li> 標(biāo)簽里面 |
地區(qū) | 在第 3 個(gè)<li> 標(biāo)簽里面 |
關(guān)注者數(shù)量 | 在第 4 個(gè)<li> 標(biāo)簽里面 |
那么我們就可以開(kāi)始制定策略了。
名字:先獲取所有的<a>
標(biāo)簽民傻,取第二個(gè)<a>
的 text
胰默。
鏈接:利用上一步獲取到的所有標(biāo)簽场斑,取第一個(gè)或者第二個(gè)<a>
的href
屬性。
上映日期等等我們就先取到所有的<li>
標(biāo)簽牵署,依次取出里面的text
的值就是我們所需要的目標(biāo)了漏隐。
那就開(kāi)始寫代碼了!
from bs4 import BeautifulSoup # 從bs4引入BeautifulSoup
# 讀取文件內(nèi)容到html變量里面
file_obj = open('douban.html', 'r') # 以讀方式打開(kāi)文件名為douban.html的文件
html = file_obj.read() # 把文件的內(nèi)容全部讀取出來(lái)并賦值給html變量
file_obj.close() # 關(guān)閉文件對(duì)象
soup = BeautifulSoup(html, 'lxml') # 初始化BeautifulSoup
# print(soup) # 輸出BeautifulSoup轉(zhuǎn)換后的內(nèi)容
all_movies = soup.find('div', id="showing-soon") # 先找到最大的div
# print(all_movies) # 輸出最大的div的內(nèi)容
for each_movie in all_movies.find_all('div', class_="item"): # 從最大的div里面找到影片的div
# print(each_movie) # 輸出每個(gè)影片div的內(nèi)容
all_a_tag = each_movie.find_all('a') # 找到所有的a標(biāo)簽
all_li_tag = each_movie.find_all('li') # 找到所有的li標(biāo)簽
movie_name = all_a_tag[1].text # 從第二個(gè)a標(biāo)簽的文字內(nèi)容提取影片名字
moive_href = all_a_tag[1]['href'] # 從第二個(gè)a標(biāo)簽的文字內(nèi)容提取影片鏈接
movie_date = all_li_tag[0].text # 從第1個(gè)li標(biāo)簽的文字內(nèi)容提取影片上映時(shí)間
movie_type = all_li_tag[1].text
movie_area = all_li_tag[2].text
movie_lovers = all_li_tag[3].text
print('名字:{}奴迅,鏈接:{}青责,日期:{},類型:{}半沽,地區(qū):{}爽柒, 關(guān)注者:{}'.format(
movie_name, moive_href, movie_date, movie_type, movie_area, movie_lovers))
運(yùn)行效果:
-
合并 請(qǐng)求網(wǎng)頁(yè) 與 解析網(wǎng)頁(yè) 的代碼
合并代碼我們就可以去掉保存文件和讀取文件的部分啦~,這就是最終版本的代碼了者填。
import requests
from bs4 import BeautifulSoup # 從bs4引入BeautifulSoup
#請(qǐng)求網(wǎng)頁(yè)
# 2019-12-23更新浩村,解決不能獲取到響應(yīng)的問(wèn)題
url = "https://movie.douban.com/cinema/later/chengdu/" # URL不變
# 新增偽裝成瀏覽器的header
fake_headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; '\
'WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'
}
response = requests.get(url, headers=fake_headers) # 請(qǐng)求參數(shù)里面把假的請(qǐng)求header加上
# 解析網(wǎng)頁(yè)
# 初始化BeautifulSoup方法一:利用網(wǎng)頁(yè)字符串自帶的編碼信息解析網(wǎng)頁(yè)
soup = BeautifulSoup(response.content.decode('utf-8'), 'lxml')
# 初始化BeautifulSoup方法二:手動(dòng)指定解析編碼解析網(wǎng)頁(yè)
# soup = BeautifulSoup(response.content, 'lxml', from_encoding='utf-8')
# print(soup) # 輸出BeautifulSoup轉(zhuǎn)換后的內(nèi)容
all_movies = soup.find('div', id="showing-soon") # 先找到最大的div
# print(all_movies) # 輸出最大的div的內(nèi)容
for each_movie in all_movies.find_all('div', class_="item"): # 從最大的div里面找到影片的div
# print(each_movie) # 輸出每個(gè)影片div的內(nèi)容
all_a_tag = each_movie.find_all('a')
all_li_tag = each_movie.find_all('li')
movie_name = all_a_tag[1].text
moive_href = all_a_tag[1]['href']
movie_date = all_li_tag[0].text
movie_type = all_li_tag[1].text
movie_area = all_li_tag[2].text
movie_lovers = all_li_tag[3].text
print('名字:{},鏈接:{}占哟,日期:{}心墅,類型:{},地區(qū):{}榨乎, 關(guān)注者:{}'.format(
movie_name, moive_href, movie_date, movie_type, movie_area, movie_lovers))
順便布置個(gè)作業(yè): 試著自己把影片海報(bào)的鏈接給爬下來(lái)并輸出怎燥。
?
-
總結(jié)
本章,我們利用了上一章所學(xué)的用 jupyter 編寫代碼蜜暑、requests 請(qǐng)求網(wǎng)頁(yè)的技能铐姚。
新學(xué)習(xí)了如何從目標(biāo)網(wǎng)頁(yè)提取我們需要的信息。需要掌握的是BeautifulSoup的簡(jiǎn)單使用肛捍。
學(xué)會(huì)把請(qǐng)求和解析分開(kāi)來(lái)完成隐绵,這樣代碼會(huì)更加具有結(jié)構(gòu)性,一個(gè)一個(gè)模塊完成了拙毫,最后拼接起來(lái)依许,就是摩天大廈了!
教程可能會(huì)比較長(zhǎng)缀蹄,其實(shí)就一個(gè)30行的代碼峭跳,為了講的詳細(xì),所以可能有很多廢話缺前。能夠認(rèn)真看到這里的蛀醉,那肯定是非常有恒心有耐心的人。
另外衅码,寫代碼不要老是復(fù)制哦滞欠,一定要試著自己寫,寫代碼的過(guò)程非常重要肆良。
?
- 附上BeautifulSoup 的文檔:
本節(jié)到此結(jié)束筛璧,下一節(jié)是關(guān)于保存爬取的數(shù)據(jù)的教程逸绎。感謝觀看。
?
?
傳送門:
下一章:
所有的章節(jié):
- 爬蟲(chóng)入門教程①— 爬蟲(chóng)簡(jiǎn)介
- 爬蟲(chóng)入門教程②— 必備知識(shí)基礎(chǔ)(一)反爬蟲(chóng)簡(jiǎn)介
- 爬蟲(chóng)入門教程③— 必備知識(shí)基礎(chǔ)(二)HTTP請(qǐng)求簡(jiǎn)介
- 爬蟲(chóng)入門教程④— 必備知識(shí)基礎(chǔ)(三)網(wǎng)頁(yè)的構(gòu)成
- 爬蟲(chóng)入門教程⑤— 安裝Python
- 爬蟲(chóng)入門教程⑥— 安裝爬蟲(chóng)常用工具包
- 爬蟲(chóng)入門教程⑦— jupyter與requests的初步使用
- [爬蟲(chóng)入門教程⑧— BeautifulSoup解析豆瓣即將上映的電影信息]
- 爬蟲(chóng)入門教程⑨— 用html和csv文件保存爬取到的數(shù)據(jù)
- 爬蟲(chóng)入門教程⑩— 用漂亮的圖表展示爬取到的數(shù)據(jù)