重要知識點
-
XPath 概述:XPath 是一門可以在 XML 文件中查找信息的語言,也可用于 HTML 文件。它功能強大,提供簡潔明了的路徑表達式和多個函數,用于字符串、數值、時間比較等。1999 年成為 W3C 標準,常用于爬蟲中抓取網頁信息。
-
XPath 解析操作:在 Python 中,常用 lxml 模塊進行 XPath 解析,該模塊底層用 C 語言編寫,解析效率高。需通過“pip install lxml”命令安裝。
-
解析 HTML:有 parse()方法用于解析本地 HTML 文件;HTML()方法用于解析字符串類型的 HTML 代碼和服務器返回的 HTML 代碼。
-
獲取所有節點:使用“//*”獲取 HTML 代碼中的所有節點。
-
獲取子節點:用“/”獲取直接子節點,“//”獲取子孫節點。
-
獲取父節點:使用“..”獲取一個節點的父節點。
-
獲取文本:用 text()方法獲取 HTML 代碼中的文本。
-
屬性匹配:使用“[@]”實現節點屬性的匹配,包括單屬性、多屬性匹配以及屬性多值匹配。
-
-
案例:爬取豆瓣電影 Top250 中的電影信息
-
分析請求地址:豆瓣電影 Top250 首頁有 10 頁內容,每頁 25 個電影信息。每頁的 URL 地址規律為間隔“25”。
-
分析信息位置:通過瀏覽器“開發者工具”查看電影名稱、導演、主演、電影評分等信息對應的 HTML 代碼位置。
-
爬蟲代碼實現:使用 requests 模塊發送網絡請求,lxml 模塊中的 XPath 解析器提取電影的相關信息。
-
相應重要代碼
# 導入 etree 子模塊
from lxml import etree# 8.2.1 解析本地的 HTML 文件
parser = etree.HTMLParser()
html = etree.parse("demo.html", parser=parser)
html_txt = etree.tostring(html, encoding="utf-8")
print(html_txt.decode('utf-8'))# 8.2.2 解析字符串類型的 HTML 代碼
html_str = """
<html><head><title>標題文檔</title></head><body><img src="./demo_files/logo1.png" /><br />hello 明日科技</body>
</html>
"""
html = etree.HTML(html_str)
html_txt = etree.tostring(html, encoding="utf-8")
print(html_txt.decode('utf-8'))# 8.2.3 解析服務器返回的 HTML 代碼(示例為發送網絡請求后解析)
import requests
from requests.auth import HTTPBasicAuth
url = 'http://example.com'
auth = HTTPBasicAuth('admin', 'admin')
response = requests.get(url=url, auth=auth)
if response.status_code == 200:html = etree.HTML(response.text)html_txt = etree.tostring(html, encoding="utf-8")print(html_txt.decode('utf-8'))# 8.2.4 獲取所有節點
html_str = """
<div class="level_one on"><ul><li><a href="/index/index/view/id/1.html" title="什么是 Java" class="on">什么是 Java</a></li><li><a href="javascript:" onclick="login(0)" title="Java 的版本">Java 的版本</a></li><li><a href="javascript:" onclick="login(0)" title="Java API 文檔">Java API 文檔</a></li><li><a href="javascript:" onclick="login(0)" title="JDK 的下載">JDK 的下載</a></li><li><a href="javascript:" onclick="login(0)" title="JDK 的安裝">JDK 的安裝</a></li><li><a href="javascript:" onclick="login(0)" title="配置 JDK">配置 JDK</a></li></ul>
</div>
"""
html = etree.HTML(html_str)
node_all = html.xpath("//*")
print("數據類型:", type(node_all))
print("數據長度:", len(node_all))
print("數據內容:", node_all)
print("節點名稱:", [i.tag for i in node_all])# 8.2.5 獲取子節點(直接子節點和子孫節點)
html_str = """
<div class="level_one on"><ul><li><a href="/index/index/view/id/1.html" title="什么是 Java" class="on">什么是 Java</a><a>Java</a></li><li><a href="javascript:" onclick="login(0)" title="Java 的版本">Java 的版本</a></li><li><a href="javascript:" onclick="login(0)" title="Java API 文檔"><a>a 節點中的 a 節點</a></a></li></ul>
</div>
"""
html = etree.HTML(html_str)
a_all = html.xpath("//li/a")
print("所有子節點 a:", a_all)
print("獲取指定 a 節點:", a_all[1])
a_txt = etree.tostring(a_all[1], encoding="utf-8")
print("獲取指定節點 HTML 代碼:", a_txt.decode('utf-8'))# 獲取子孫節點
a_all = html.xpath("//ul//a")
print("所有子節點 a:", a_all)
print("獲取指定 a 節點:", a_all[4])
a_txt = etree.tostring(a_all[4], encoding="utf-8")
print("獲取指定節點 HTML 代碼:", a_txt.decode('utf-8'))# 8.2.6 獲取父節點
html_str = """
<div class="level_one on"><ul><li><a href="/index/index/view/id/1.html" title="什么是 Java" class="on">什么是 Java</a></li><li><a href="javascript:" onclick="login(0)" title="Java 的版本">Java 的版本</a></li></ul>
</div>
"""
html = etree.HTML(html_str)
a_all_parent = html.xpath("//a/..")
print("所有 a 的父節點:", a_all_parent)
print("獲取指定 a 的父節點:", a_all_parent[0])
a_txt = etree.tostring(a_all_parent[0], encoding="utf-8")
print("獲取指定節點 HTML 代碼:\n", a_txt.decode('utf-8'))# 8.2.7 獲取文本
html_str = """
<div class="level_one on"><ul><li><a href="/index/index/view/id/1.html" title="什么是 Java" class="on">什么是 Java</a></li><li><a href="javascript:" onclick="login(0)" title="Java 的版本">Java 的版本</a></li></ul>
</div>
"""
html = etree.HTML(html_str)
a_text = html.xpath("//a/text()")
print("所有 a 節點中文本信息:", a_text)# 8.2.8 屬性匹配
html_str = """
<div class="video scroll"><div class="level">什么是 Java</div><div class="level">Java 的版本</div>
</div>
"""
html = etree.HTML(html_str)
div_one = html.xpath("//div[@class='level']/text()")
print(div_one)# 多屬性匹配
html_str = """
<div class="video_scroll"><div class="level" id="one">什么是 Java</div><div class="level">Java 的版本</div>
</div>
"""
html = etree.HTML(html_str)
div_all = html.xpath("//div[@class='level' and @id='one']/text()")
print(div_all)# 8.2.9 獲取屬性
html_str = """
<div class="video scroll"><li class="level" id="one">什么是 Java</li>
</div>
"""
html = etree.HTML(html_str)
li_class = html.xpath("//div/li/@class")
li_id = html.xpath("//div/li/@id")
print("class 屬性值:", li_class)
print("id 屬性值:", li_id)# 8.2.10 按序獲取屬性值
html_str = """
<div class="video_scroll"><li><a href="javascript:" onclick="login(0)" title="Java API 文檔">Java API 文檔</a></li><li><a href="javascript:" onclick="login(0)" title="JDK 的下載">JDK 的下載</a></li><li><a href="javascript:" onclick="login(0)" title="JDK 的安裝">JDK 的安裝</a></li><li><a href="javascript:" onclick="login(0)" title="配置 JDK">配置 JDK</a></li>
</div>
"""
html = etree.HTML(html_str)
li_all = html.xpath("//div/li/a/@title")
print("所有屬性值:", li_all)
li_first = html.xpath("//div/li[1]/a/@title")
print("第一個屬性值:", li_first)
li_four = html.xpath("//div/li[4]/a/@title")
print("第四個屬性值:", li_four)# 使用節點軸獲取節點內容(示例為獲取 li[2] 所有祖先節點)
html_str = """
<div class="video_scroll"><li><a href="javascript:" onclick="login(0)" title="Java API 文檔">Java API 文檔</a></li><li><a href="javascript:" onclick="login(0)" title="JDK 的下載">JDK 的下載</a></li><li><a href="javascript:" onclick="login(0)" title="JDK 的安裝">JDK 的安裝</a></li>
</div>
"""
html = etree.HTML(html_str)
ancestors = html.xpath("//li[2]/ancestor::*")
print("li[2] 所有祖先節點名稱:", [i.tag for i in ancestors])# 爬取豆瓣電影 Top250 中的電影信息(部分代碼)
from lxml import etree
import time
import random
import requests
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; wow64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'}def processing(strs):s = ""for n in strs:s = s + "".join(n.split())return sdef get_movie_info(url):response = requests.get(url, headers=header)html = etree.HTML(response.text)div_all = html.xpath("//div[@class='info']")for div in div_all:names = div.xpath("./div[@class='hd']/a//span/text()")name = processing(names)infos = div.xpath("./div[@class='bd']/p/text()")info = processing(infos)score = div.xpath("./div[@class='bd']/div/span[2]/text()")evaluation = div.xpath("./div[@class='bd']/div/span[4]/text()")summary = div.xpath("./div[@class='bd']/p[@class='quote']/span/text()")print("電影名稱:", name)print("導演與演員:", info)print("電影評分:", score)print("評價人數:", evaluation)print("電影總結:", summary)print("- -分隔線- -")if __name__ == "__main__":for i in range(0, 250, 25):url = "https://movie.douban.com/top250?start={page}&filter=".format(page=i)get_movie_info(url)time.sleep(random.randint(1, 3))