之前分享了一篇使用requests庫爬取豆瓣電影250的文章,今天繼續分享使用xpath爬取貓眼電影熱播口碑榜
XPATH語法
XPATH(XML Path Language)是一門用於從XML文件中查找信息的語言。通用適用於從HTML文件中查找數據。工欲善其事必先利其器,我們首先來了解XPATH常用的語法規則。
常用匹配規則:
屬性 | 匹配規則描述 |
---|---|
nodename | 匹配此節點的所有子節點 |
/ | 匹配當前節點的直接子節點,不包含孫節點 |
// | 匹配當前節點的所有子孫節點 |
. | 匹配當前節點 |
.. | 匹配當前節點的父節點 |
@ | 匹配屬性值 |
XPATH的匹配功能很強大,上面6種匹配規則可以搭配使用,通過上面的6種匹配規則即可爬取到網頁上所有的我們想要的數據。
使用下面的HTML文檔介紹上述6種規則的搭配使用。
<html>
<div id="div_id1" class="div_class1">
<ul>
<li class="li_item1"><a href="www.bigdata17.com">Summer哥的自留地</a></li>
<li class="li_item2 li"><a href="li_test.html">test li</a></li>
</ul>
<li>20</li>
<li>30</li>
<ul>
</ul>
</div>
</html>
匹配表達式 | 結果 |
---|---|
//* | 匹配網頁中所有的節點 |
//div | 匹配所有div節點 |
//div/li | 匹配所有div節點的所有li節點 |
//a[@href="www.bigdata17.com"/..] | 匹配href屬性為www.bigdata17.com的A節點的父節點 |
//li[@class="li_item1"] | 匹配所有li元素,且為class屬性為"li_item1" |
//li[@class] | 匹配所有擁有class屬性的li元素 |
//li/a/@href | 獲取所有li元素a子元素的href屬性值,注意和//li[@class="li_item1"的且 |
//li//text() | 過去li節點所有子節點的文本 |
//li[@class="li_item1"]/a/text() | 獲取class屬性為li_item1的li節點所有a子節點的文本 |
//li[contains(@class,"li")]/a/text() | 獲取class屬性值包含li的li節點所有a子節點的文本 |
//div[contains(@class,"div") and @id="div_id1"]/ul | 獲取所有class屬性包含“div”且id屬性值為“div_id1”的div節點的ul子節點 |
/div/ul[li>20] | 選取div節點的所有 ul節點,且其中的li節點的值須大於20 |
/div/ul[1] | 匹配屬於div節點的第一個 ul節點。 |
/div/ul[last()] | 匹配屬於div 子節點的最后一個ul節點 |
/div/ul[last()-1] | 匹配屬於div 子節點的倒數第二個ul節點 |
/div/ul[position() < 3] | 匹配最前面的兩個屬於div元素的ul子元素 |
通過上面的匹配規則,我們就可以使用XPATH來解析爬取貓眼電影國內票房榜的數據。
XPATH要配合requests一起使用,使用requests抓取網頁信息,然后使用XPATH解析網頁信息,XPATH在lxml庫中,因此需要在pycharm中安裝lxml。
1、獲取取貓眼電影熱播口碑榜HTML文件
下面是抓取貓眼電影熱播口碑榜的代碼:
from lxml import etree
import requests
url = 'http://maoyan.com/board/1'
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
response = requests.get(url,headers=headers)
html = response.text
2、提取電影名
現在瀏覽器的開發者工具都支持提取xpath規則,具體步驟如下:
首先在瀏覽器中打開網址,按下F12,ctrl+f查找電影名,鼠標右鍵彈出的菜單,點擊Copy選項,點擊Copy Xpath。到此就可以把電影名稱的xpath匹配規則提取出來:
電影名稱提取的規則是:
//*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[1]/p[1]/a
我們使用這個規則看下是否能提取出電影名稱,代碼如下:
from lxml import etree
import requests
url = 'http://maoyan.com/board/7'
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
response = requests.get(url,headers=headers)
html = response.text
movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[1]/p[1]/a/text()'
s = etree.HTML(html)
movie_name = s.xpath(movie_name_xpath)
print(movie_name)
運行結果:[<Element a at 0x35f5248>]
上面的結果顯示抓取到的是a元素,就是html中的a標簽,要想獲取該元素中的文本值,必須在xpath匹配規則追加/text(),下面是追加/text()后的代碼及運行結果:
from lxml import etree
import requests
url = 'http://maoyan.com/board/1'
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
response = requests.get(url,headers=headers)
html = response.text
movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[1]/p[1]/a/text()'
s = etree.HTML(html)
movie_name = s.xpath(movie_name_xpath)
print(movie_name)
運行結果['嗝嗝老師']
這里只是提取一部電影的名稱,我們要想提取當前網頁的所有電影的名稱,匹配規則怎么寫呢?
下面是當前頁10部電影的xpath匹配規則
//*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[1]/p[1]/a
//*[@id="app"]/div/div/div/dl/dd[2]/div/div/div[1]/p[1]/a
//*[@id="app"]/div/div/div/dl/dd[3]/div/div/div[1]/p[1]/a
//*[@id="app"]/div/div/div/dl/dd[4]/div/div/div[1]/p[1]/a
//*[@id="app"]/div/div/div/dl/dd[5]/div/div/div[1]/p[1]/a
//*[@id="app"]/div/div/div/dl/dd[6]/div/div/div[1]/p[1]/a
//*[@id="app"]/div/div/div/dl/dd[7]/div/div/div[1]/p[1]/a
//*[@id="app"]/div/div/div/dl/dd[8]/div/div/div[1]/p[1]/a
//*[@id="app"]/div/div/div/dl/dd[9]/div/div/div[1]/p[1]/a
//*[@id="app"]/div/div/div/dl/dd[10]/div/div/div[1]/p[1]/a
發現dd的數字會變化,其他的都不變,因此用通配符“*”代替dd節點中的數字,提取當前頁所有電影名字的xpath規則為:
//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[1]/a
看下最后的運行結果是什么。
from lxml import etree
import requests
url = 'http://maoyan.com/board/1'
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
response = requests.get(url,headers=headers)
html = response.text
movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[1]/a/text()'
s = etree.HTML(html)
movie_name = s.xpath(movie_name_xpath)
print(movie_name)
運行結果:['嗝嗝老師', '毒液:致命守護者', '無名之輩', '恐龍王', '流浪貓鮑勃', '無雙', '名偵探柯南:零的執行人', '颶風奇劫', '影', '你好,之華']
可見使用通配符*把所有的電影名稱都提取出來了。
3、提取電影圖片鏈接
通過上步驟獲取圖片的xpath匹配規則為:
//*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]
通過開發者工具知道img節點有三個屬性,分別是alt,class和src。
其中src的是圖片的地址,在xpath提取規則追加上@src,變為:
//*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]/@src
看下這個xpath規則是否能提取到圖片的鏈接地址:
from lxml import etree
import requests
url = 'http://maoyan.com/board/7'
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
response = requests.get(url,headers=headers)
html = response.text
movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]/@src'
s = etree.HTML(html)
movie_img = s.xpath(movie_img_xpath)
print(movie_img)
運行的結果是:[]
怎么會得不到src屬性的值呢?難道src屬性不存在?
通過鼠標右鍵查看網頁源文件:
原來src變成了data-src。修改xpath規則后看下能否提取出電影圖片鏈接:
from lxml import etree
import requests
url = 'http://maoyan.com/board/7'
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
response = requests.get(url,headers=headers)
html = response.text
movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]/@data-src'
s = etree.HTML(html)
movie_img = s.xpath(movie_img_xpath)
print(movie_img)
運行結果:
['http://p0.meituan.net/movie/36f1a50b4eae6aa93e3f7a373fb6ee89991083.jpg@160w_220h_1e_1c']
電影圖片鏈接提取成功。
這是提取一部電影的xpath規則,下面是當前頁面10部電影圖片的規則:
//*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]/@data-src
//*[@id="app"]/div/div/div/dl/dd[2]/a/img[2]/@data-src
//*[@id="app"]/div/div/div/dl/dd[3]/a/img[2]/@data-src
...
...
...
//*[@id="app"]/div/div/div/dl/dd[9]/a/img[2]/@data-src
//*[@id="app"]/div/div/div/dl/dd[10]/a/img[2]/@data-src
觀察發現dd的數字會變化,其他的都不變,因此用通配符“*”代替dd節點中的數字,提取當前頁所有電影圖片鏈接的xpath規則為:
//*[@id="app"]/div/div/div/dl/dd[*]/a/img[2]/@data-src
以此類推,通過上面的方式提取出當前頁所有電影名稱,圖片地址,主演,上映時間,評分的xpath匹配規則:
movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[1]/a/text()'
movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/a/img[2]/@data-src'
movie_actor_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[2]/text()'
movie_release_time_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[3]/text()'
movie_score_xpath =
'//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[2]/p/i/text()'
爬取貓眼電影國內熱播榜的完整代碼如下:
# coding:utf-8
from lxml import etree
import requests
#獲取網頁
def getHtml(url):
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
response = requests.get(url,headers=headers)
html = response.text
return html
#
# movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[2]/p/i/text()'
# s = etree.HTML(html)
# movie_img = s.xpath(movie_img_xpath)
# print(movie_img)
#解析網頁
def parseHtml(html):
s = etree.HTML(html)
movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[1]/a/text()'
movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/a/img[2]/@data-src'
movie_actor_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[2]/text()'
movie_release_time_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[3]/text()'
movie_score_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[2]/p/i/text()'
movie_name = s.xpath(movie_name_xpath)
movie_img = s.xpath(movie_img_xpath)
movie_actor = s.xpath(movie_actor_xpath)
movie_score = s.xpath(movie_score_xpath)
movie_release_time = s.xpath(movie_release_time_xpath)
for i in range(len(movie_name)):
print('電影名稱:' + movie_name[i])
print('主演:' + movie_actor[i].strip())
print('圖片鏈接:' + movie_img[i].strip())
print('評分:' + movie_score[2*i] + movie_score[2*i + 1])
print(movie_release_time[i])
print('-------------------------------------------強力分割線-------------------------------------------')
def main():
url = 'http://maoyan.com/board/7'
html = getHtml(url)
parseHtml(html)
if __name__ == '__main__':
main()
總結:
在使用開發者工具提取xpath規則獲取不到相應的數據時,要注意xpath規則是否准確,有些瀏覽器會加上一些多余的標簽,或者將節點的屬性名改掉,例如上面例子中將的img節點的src屬性變為data-src。結合查看源文件都可以獲取到正確的xpath規則。