Ⅰ 爬虫之xpath模块
【一】xpath引言
【1】介绍
xpath在Python的爬虫学习中,起着举足轻重的地位,对比正则表达式 re两者可以完成同样的工作,实现的功能也差不多,但xpath明显比re具有优势,在网页分析上使re退居二线。
xpath 全称为XML Path Language 一种小型的查询语言
【2】优点
可在XML中查找信息
支持HTML的查找
通过元素和属性进行导航
python开发使用XPath条件: 由于XPath属于lxml库模块,所以首先要安装库lxml
【3】安装
pip install lxml
【4】使用
from lxml import etree
selector= etree. HTML( "源码" )
selector. xpath( "表达式" )
【二】路径表达式
表达式
描述
实例
解析
/
从根节点选取
/body/div[1]
选取根结点下的body下的第一个div标签
//
从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
//a
选取文档中所有的a标签
./
当前节点再次进行xpath
./a
选取当前节点下的所有a标签
@
选取属性
//@calss
选取所有的class属性
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>
</html>
"""
from lxml import etree
tree = etree. HTML( html_doc)
a_list= tree. xpath( "/html/body/p/a" )
for a in a_list:
href = a. xpath( "./@href" )
text = a. xpath( "./text()" )
print ( href)
print ( text)
【三】谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点。
谓语被嵌在方括号中。
在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
路径表达式
结果
/ul/li[1]
选取属于 ul子元素的第一个 li元素。
/ul/li[last()]
选取属于 ul子元素的最后一个 li元素。
/ul/li[last()-1]
选取属于 ul子元素的倒数第二个 li元素。
//ul/li[position()❤️]
选取最前面的两个属于 ul元素的子元素的 li元素。
//a[@title]
选取所有拥有名为 title的属性的 a元素。
//a[@title='xx']
选取所有 a元素,且这些元素拥有值为 xx的 title属性。
//a[@title>10] > < >= <= !=
选取 a元素的所有 title元素,且其中的 title元素的值须大于 10。
/body/div[@price>35.00]
选取body下price元素值大于35的div节点
【四】选取未知节点
【1】语法
XPath 通配符可用来选取未知的 XML 元素。
通配符
描述
*
匹配任何元素节点。
@*
匹配任何属性节点。
node()
匹配任何类型的节点。
【2】实例
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式
结果
/ul/*
选取 bookstore 元素的所有子元素。
//*
选取文档中的所有元素。
//title[@*]
选取所有带有属性的 title 元素。
//node()
获取所有节点
【五】选取若干路径
【1】语法
通过在路径表达式中使用 | 运算符,您可以选取若干个路径。
【2】实例
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式
结果
//book/title | //book/price
选取 book 元素的所有 title 和 price 元素。
//title | //price
选取文档中的所有 title 和 price 元素。
/bookstore/book/title | //price
选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。
(1)逻辑运算
// div[ @id = "head" and @class = "s_down" ]
// title | // price
(2)属性查询
// div[ @id ]
// div[ @id = "maincontent" ]
// @class
// li[ @name= "xx" ] // text( )
(3)获取第几个标签 索引从1开始
tree. xpath( '//li[1]/a/text()' )
tree. xpath( '//li[last()]/a/text()' )
tree. xpath( '//li[last()-1]/a/text()' )
(4)模糊查询
// div[ contains( @id , "he" ) ]
// div[ starts- with ( @id , "he" ) ]
// div/ h1/ text( )
// div/ a/ @href
// *
// * [ @class = "xx" ]
c = tree. xpath( '//li/a' ) [ 0 ]
result= etree. tostring( c, encoding= 'utf-8' )
print ( result. decode( 'UTF-8' ) )
【六】案例
from lxml import etree
doc = '''
<html>
<head>
<base href='http://example.com/' /> <!-- 设置基准链接 -->
<title>Example website</title> <!-- 设置网页标题 -->
</head>
<body>
<div id='images'>
<a href='image1' id='lqz'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
<a href='image2'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
<a href='image3'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
<a href='image4'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
<a href='image5' class='li li-item' name='items'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
<a href='image6' name='items'><span><h5>test</h5></span>Name: My image 6 <br /><img src='image6_thumb.jpg' /></a>
</div>
</body>
</html>
'''
html = etree. HTML( doc)
all_nodes = html. xpath( '//*' )
print ( all_nodes)
head_node = html. xpath( '//head' )
print ( head_node)
child_nodes = html. xpath( '//div/a' )
descendant_nodes = html. xpath( '//body//a' )
print ( child_nodes)
print ( descendant_nodes)
parent_node = html. xpath( '//body//a[1]/..' )
print ( parent_node)
matched_nodes = html. xpath( '//body//a[@href="image1"]' )
print ( matched_nodes)
text = html. xpath( '//body//a[@href="image1"]/text()' )
print ( text)
href_attributes = html. xpath( '//body//a/@href' )
print ( href_attributes)
li_class_nodes = html. xpath( '//body//a[contains(@class, "li")]' )
print ( li_class_nodes)
matched_nodes = html. xpath( '//body//a[contains(@class, "li") and @name="items"]' )
print ( matched_nodes)
second_a_text = html. xpath( '//a[2]/text()' )
print ( second_a_text)
ancestors = html. xpath( '//a/ancestor::*' )
div_ancestor_node = html. xpath( '//a/ancestor::div' )
attribute_values = html. xpath( '//a[1]/attribute::*' )
child_nodes = html. xpath( '//a[1]/child::*' )
descendant_nodes = html. xpath( '//a[6]/descendant::*' )
following_nodes = html. xpath( '//a[1]/following::*' )
following_sibling_nodes = html. xpath( '//a[1]/following-sibling::*' )
print ( ancestors)
print ( div_ancestor_node)
print ( attribute_values)
print ( child_nodes)
print ( descendant_nodes)
print ( following_nodes)
print ( following_sibling_nodes)
【案例】jd爬取一些phone信息
jd.html 是你加Cookie之后拿到的页面数据 保存到本地
import requests
from fake_useragent import UserAgent
from lxml import etree
class SpiderJD ( object ) :
def __init__ ( self) :
self. headers = {
"User-Agent" : UserAgent( ) . random,
"Cookie" : "" ,
}
def save ( self, data) :
with open ( "jd.html" , "w" , encoding= "utf-8" ) as fp:
fp. write( data)
def read ( self) :
with open ( "jd.html" , "r" , encoding= "utf-8" ) as fp:
data = fp. read( )
return data
def spider_page_tree ( self) :
target_url = 'https://search.jd.com/Search'
params = {
"keyword" : "手机"
}
response = requests. get( url= target_url, headers= self. headers, params= params)
page_text = response. text
tree = etree. HTML( page_text)
return tree
def parse_good_data ( self) :
tree = self. spider_page_tree( )
li_list = tree. xpath( '//*[@id="J_goodsList"]/ul/li' )
good_data = { }
for li in li_list:
price = li. xpath( "./div/div[3]/strong/i/text()" ) [ 0 ]
title = li. xpath( "./div/div[4]/a/em/text()" ) [ 0 ]
try :
store = li. xpath( "./div/div[7]/span/a/text()" ) [ 0 ]
except Exception as e:
store = ""
try :
tag = [ i. xpath( "./text()" ) [ 0 ] for i in li. xpath( "./div/div[8]/i" ) ]
except Exception as e:
tag = ""
good_data[ title] = {
"price" : price,
"store" : store,
"tag" : tag,
}
print ( good_data)
if __name__ == '__main__' :
s = SpiderJD( )
s. parse_good_data( )
【案例】豆瓣Top250基于xpath解析
import requests
from lxml import etree
url = "https://movie.douban.com/top250?start=0"
headers = {
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36"
}
resp = requests. get( url, headers= headers)
tree = etree. HTML( resp. text)
items = tree. xpath( '//li/div[@class="item"]/div[@class="info"]' )
for item in items:
title = item. xpath( './div[@class="hd"]/a/span[1]/text()' ) [ 0 ]
rating_num = item. xpath( './div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()' ) [ 0 ]
comment_num = item. xpath( './div[@class="bd"]/div[@class="star"]/span[4]/text()' ) [ 0 ]
print ( title, rating_num, comment_num)
Ⅱ request-html模块
【一】引言
作者致力于封装更好用的代码
使用requests封装了python内置模块urllib
经过重构又封装了 requests+lxml
requests+lxml 爬取 + 解析 合二为一
requests-html库是一个Python实现的网页解析库,它使用了Requests和BeautifulSoup库的组合,为用户提供了简单而强大的网页解析功能。
【二】安装
可以使用pip命令安装requests-html库
pip install requests- html
【三】导入
导入requests-html库,并创建HTMLSession对象
from requests_html import HTMLSession
session = HTMLSession( )
【四】发送请求
使用session对象发送HTTP请求,获取网页内容
response = session. get( 'http://example.com' )
【五】解析网页
可以使用.html属性将网页内容解析为BeautifulSoup对象
soup = response. html
【六】查找元素
可以使用CSS选择器或XPath表达式在网页中查找元素
elements = soup. find( 'div.classname' )
elements = soup. xpath( '//div[@class="classname"]' )
【七】提取数据
text = element. text
attribute = element. attrs[ 'attribute_name' ]
【八】案例及注解
【1】方式一:CSS选择器语法
from requests_html import HTMLSession
from fake_useragent import UserAgent
session = HTMLSession( )
tag_url = "https://www.baidu.com/"
headers = {
"User-Agent" : UserAgent( ) . chrome
}
response = session. get( url= tag_url, headers= headers)
soup = response. html
ul_list = soup. find( 'ul' )
li_list = ul_list[ 1 ] . find( "li" )
data_list = [ ]
for li in li_list:
href = li. find( "a" ) [ 0 ] . attrs[ "href" ]
title = li. find( "a > span.title-content-title" ) [ 0 ] . text
data_list. append( {
"title" : title,
"href" : href,
} )
print ( data_list)
【2】方式二:xpath语法
from requests_html import HTMLSession
from fake_useragent import UserAgent
session = HTMLSession( )
tag_url = "https://www.baidu.com/"
headers = {
"User-Agent" : UserAgent( ) . chrome
}
response = session. get( url= tag_url, headers= headers)
soup = response. html
li_list = soup. xpath( '//*[@id="hotsearch-content-wrapper"]/li' )
data_list = [ ]
for li in li_list:
href = li. xpath( "//a/@href" ) [ 0 ]
title = li. xpath( '//a/span[@class="title-content-title"]/text()' ) [ 0 ]
data_list. append( {
"title" : title,
"href" : href,
} )
print ( data_list)
Ⅲ Selenium框架
【一】Selenium框架介绍
【1】web自动化
随着互联网的发展,前端技术也在不断变化,数据的加载方式也不再是单纯的服务端渲染了。
现在你可以看到很多网站的数据可能都是通过接口的形式传输的,
或者即使不是接口那也是一些 JSON 的数据,然后经过 JavaScript 渲染得出来的。
这时,如果你还用 requests 来爬取内容,那就不管用了。
因为 requests 爬取下来的只能是服务器端网页的源码,这和浏览器渲染以后的页面内容是不一样的。
因为,真正的数据是经过 JavaScript 执行后,渲染出来的,数据来源可能是 Ajax,也可能是页面里的某些 Data,或者是一些 ifame 页面等。
不过,大多数情况下极有可能是 Ajax 接口获取的。
所以,很多情况我们需要分析 Ajax请求,分析这些接口的调用方式,通过抓包工具或者浏览器的“开发者工具”,找到数据的请求链接,然后再用程序来模拟。
但是,抓包分析流的方式,也存在一定的缺点。
因为有些接口带着加密参数,比如 token、sign 等等,模拟难度较大;
那有没有一种简单粗暴的方法,
这时 Puppeteer、Pyppeteer、Selenium、Splash 等自动化框架出现了。
使用这些框架获取HTML源码,这样我们爬取到的源代码就是JavaScript 渲染以后的真正的网页代码,数据自然就好提取了。
同时,也就绕过分析 Ajax 和一些 JavaScript 逻辑的过程。
这种方式就做到了可见即可爬,难度也不大,同时适合大批量的采集。
【2】Selenium优缺点
作为一款知名的Web自动化测试框架,支持大部分主流浏览器,提供了功能丰富的API接口,常常被我们用作爬虫工具来使用。
然而selenium的缺点也很明显
速度太慢
对版本配置要求严苛
最麻烦是经常要更新对应的驱动
selenium最初是一个自动化测试工具,
而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题
selenium本质是通过驱动浏览器,完全模拟浏览器的操作,
比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器
【二】Selenium框架安装
【1】安装selenium包
pip install selenium
首次安装会有进度条,而且装出来是多个包(依赖于其他第三方库)。
如果安装慢(默认连接官网),可以指定国内源。
pip install selenium - i https: // mirrors. aliyun. com/ pypi/ simple/
【2】安装chrome驱动
选择与你浏览器版本差不多的 ,以及电脑配置一样的版本
【3】测试驱动
from selenium. webdriver import Chrome
from selenium. webdriver. chrome. service import Service
import time
service = Service( executable_path= "./chromedriver.exe" )
browser = Chrome(
service= service
)
browser. get( 'https://www.baidu.com' )
time. sleep( 3 )
【4】案例
import time
from selenium. webdriver import Chrome
from selenium. webdriver. chrome. service import Service
from selenium. webdriver. common. by import By
browser = Chrome( service= Service( './chromedriver.exe' ) )
browser. get( 'https://www.baidu.com/' )
input_search = browser. find_element( By. ID, "kw" )
input_search. send_keys( 'Python' )
time. sleep( 3 )
btn_search = browser. find_element( By. ID, "su" )
btn_search. click( )
time. sleep( 3 )
browser. save_screenshot( './baidu.png' )
browser. close( )
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY