1. xpath安装及基本语法
环境的安装:pip install lxml
-
1.xpath的解析原理
实例化一个etree类型的对象,且将页面源码数据加载到该对象中
需要调用该对象的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取 -
2.etree对象的实例化
etree.parse(fileNane) #本地的html文件
etree.HTML(page_text) #声明了一段HTML文本,调用HTML类进行初始化,构造了一个XPath解析对象
xpath方法返回的永远是一个列表实例化报错:爬虫中lxml.etree.XMLSyntaxError问题
解决方法:
修改代码如下:
1. 解析本地的HTML源码文件,假设其为:XX.html,根据实际更改。
parser = etree.HTMLParser(encoding="utf-8")
tree = etree.parse('XX.html', parser=parser)
2. 解析从互联网获取的HTML源码数据。
page_text = requests.get(url, headers).text
parser = etree.HTMLParser(encoding="utf-8")
tree = etree.HTML(page_text, parser=parser)
-
3.标签定位
xpath表达式中最最侧的/表示的含义是说,当前定位的标签必须从根节点开始进行定位
xpath表达式中最左侧的//表示可以从任意位置进行标签定位
xpath表达式中非最左侧的//表示的是多个层级的意思
xpath表达式中非最左侧的/表示的是一个层级的意思 -
4.属性定位
//标签名[@arrtName='value']
循环中标签定位: ./表示当前标签
索引定位://标签名/li[3] #第三个li标签 -
- 提取数据
- 5.1取文本:
/text():取直系的文本内容
//text():取所有的文本内容,循环中不能再用索引,例如文本中有br标签分割 - 5.2取属性:
tag/@attrName
举例:
from lxml import etree
tree = etree.parse('./test.html')
tree.xpath('/html/head/meta')[0] #绝对路径
tree.xpath('//meta')[0] #相对路径,将整个页面源码中所有的meta进行定位
tree.xpath('/html//meta')[0]
#属性定位
tree.xpath('//div[@class="song"]')
#索引定位
tree.xpath('//div[@class="tang"]/ul/li[3]') #该索引是从1开始
tree.xpath('//div[@class="tang"]//li[3]') #该索引是从1开始
#取文本
tree.xpath('//p[1]/text()')
tree.xpath('//div[@class="song"]//text()')
#取属性
tree.xpath('//a[@id="feng"]/@href')
2. xpath表达式语法
2.1 使用/
表示搜索层级
起始的/
表示根节点
当/
放在首位的时候,表示从根节点开始定位。
后续的/
表示层级(bs4的>
)
from lxml import etree
# 实例化好了一个etree对象,且将被解析的源码加载到了该对象中
tree = etree.parse('alice.html')
# 第一个斜杠表示从根节点开始遍历的
# 后续的斜杠表示层级递进
# 返回值为所有符合表达式规则的属性对象,使用text获取文本内容
tree.xpath('/html/body/title')[0].text
//表示跨越层级(bs4的)
from lxml import etree
# 实例化好了一个etree对象,且将被解析的源码加载到了该对象中
tree = etree.parse('alice.html')
# 第一个斜杠表示从根节点开始遍历的
tree.xpath('//title')
./表示从当前层级往下走
from lxml import etree
# 实例化好了一个etree对象,且将被解析的源码加载到了该对象中
tree = etree.parse('alice.html')
# 第一个斜杠表示从根节点开始遍历的
body = tree.xpath('//body')[0]
# 从body往下走
title = body.xpath('./title')[0]
print(title.text)
# 以下代码直接报错,因为/是从根节点开始的,不是从body开始的
title = body.xpath('/title')[0]
print(title.text)
output >> IndexError: list index out of range
2.2 定位
定位分为两种,一种是属性定位,一种是索引定位。两种方法结合使用会更加精确。
2.2.1 属性定位
语法tag[@attrName="attrValue"]
from lxml import etree
# 实例化好了一个etree对象,且将被解析的源码加载到了该对象中
tree = etree.parse('alice.html')
# 使用类名精确定位p标签
tree.xpath('/html/body/p[@class="story"]')
# 得到符合要求的列表
output >> [<Element p at 0x1c442ae1ac8>, <Element p at 0x1c442ae1e88>]
2.2.2 索引定位
索引定位就是在之前的选择器中多加入了一个索引,2.2.2.1的代码修改为下列代码
from lxml import etree
# 实例化好了一个etree对象,且将被解析的源码加载到了该对象中
tree = etree.parse('alice.html')
# 使用下标精准索引某一标签
tree.xpath('/html/body/p[@class="story"][1]')
# 得到符合要求的列表
output >> <Element p at 0x1c442ae1ac8>
注意,这里的索引下标是从1开始的,而不是从0开始
2.3 输出
- 在上面的选择器后面加入/text()输出当前标签的文本内容
- 加入//text()输出所有子标签的内容
from lxml import etree
# 实例化好了一个etree对象,且将被解析的源码加载到了该对象中
tree = etree.parse('alice.html')
# 使用text()打印输出
tree.xpath('/html/body/p[@class="story"]/text()')
# 得到文本内容
output >> ['Once upon a time there were three little sisters; and their names were\n ',
',\n ',
' and\n ',
'; and they lived at the bottom of a well.',
'...']
可以观察到,所有在a标签中的内容都没有打印出来
在使用//text()后,就可以打印出a标签的内容了
from lxml import etree
# 实例化好了一个etree对象,且将被解析的源码加载到了该对象中
tree = etree.parse('alice.html')
# 使用text()打印输出
tree.xpath('/html/body/p[@class="story"]//text()')
# 得到全部文本内容
output >> ['Once upon a time there were three little sisters; and their names were\n ',
'Elsie',
',\n ',
'Lacie',
' and\n ',
'Tillie',
'; and they lived at the bottom of a well.',
'...']
3. demo
爬取糗事百科的段子内容和作者名称
# coding:utf-8
import requests
from lxml import etree
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36',
}
url = 'https://www.qiushibaike.com/text/page/4/'
page_text = requests.get(url,headers=headers).text
#print(page_text)
tree = etree.HTML(page_text)
div_list = tree.xpath('//div[@class="col1 old-style-col1"]/div')
print(div_list)
for div in div_list:
author = div.xpath('./div[1]/a[2]/h2/text() | ./div[1]/span[2]/h2/text()')[0]
# 糗事百科中有作者和段子内容,作者分为实名用户和匿名用户,但通过对糗事百科的源码,当是匿名用户的时候,文本内容就取不到,所以返回None,但是爬取到的内容也就是None,不是想要的结果,解决: ./div[1]/a[2]/h2/text()取实名用户,./div[1]/span[2]/h2/text()取匿名用户
content = div.xpath('.//div[@class="content"]/span//text()')
content = ''.join(content)
print(author,content)
输出:
撞死一只羊
上周公司去日料店聚餐,没想到平时有女神光环的一位女生,一脱下鞋的那股酸臭味,把在场的人都纷纷「震撼」住了。臭就算了,居然还没穿袜子!可想而知那双脚的攻击性有多强!当时我的心情是已经不想干饭了,想赶紧跑。而女神自己也尴尬到跑去找卫生间洗脚。不然难以想象一顿有味道的午餐怎么吃得下去。过后我悄悄问女神,为啥那天没穿袜子,她说实在是找不到合适的袜子搭配那双鞋!
邱子是漂亮的
今天我两个同事吵架了,不管我怎么劝,他们就是不肯打架
骑着二哈啃黄瓜
闺蜜喝酒不爱去第二场,就是k t v,,,,好死不死,又被我拉去了,三杯酒下肚,就嗨起来了,比谁都会玩,中途她有电话,包厢太吵,她就出去接,一出门就被服务员告诫了:姑凉,我们这里不允许窜野台哦。。。
爬取糗事百科笑话的标题和内容
http://www.lovehhy.net/Joke/Detail
from lxml import etree
import requests
url = 'http://www.lovehhy.net/Joke/Detail/QSBK/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
'Cookie':'bdshare_firstime=1573442373487; ASP.NET_SessionId=0yoewt3nnhet3apass0u4hj5; ASPSESSIONIDQADBDDCA=AAKLABFACJHJNHHCMCKEJGJB; __51cke__=; Hm_lvt_03da7ad267ef3d61ce133d6c12f67140=1573442375,1573478536; ASPSESSIONIDSACCBCCA=BCOLDPEALOKMHFJJMHODNHGB; Hm_lpvt_lovehhy=1573479577; Hm_lvt_lovehhy=1573479577; Hm_lpvt_03da7ad267ef3d61ce133d6c12f67140=1573479707; __tins__2343955=%7B%22sid%22%3A%201573478536404%2C%20%22vd%22%3A%2011%2C%20%22expires%22%3A%201573481507039%7D; __51laig__=11'
}
joke_text = requests.get(url=url,headers=headers).text
#print(joke_text)
tree = etree.HTML(joke_text)
url_text = tree.xpath('//*[@class="post_recommend_new"]/h3/a/@href')
#url_text
for i in url_text:
qiu_url = i
print(i)
content_text = requests.get(url=qiu_url,headers=headers).text
tree = etree.HTML(content_text)
title = tree.xpath('//*[@id="read"]/h1/text()')[0]
content = tree.xpath('//*[@id="fontzoom"]/text()')[0]
print(title,content)
输出:
http://www.lovehhy.net/Yulu/View/170956
图文语录 - 生活中难免有不如意的时候
“ 生活中难免有不如意的时候 路还很长 你不要绝望 打起精神来重新出发 温暖的事以后一定会发生的 ” ?
http://www.lovehhy.net/Yulu/View/170955
图文语录 - 但我希望对方可以肯定我
“ 我喜欢能带给我正面影响的人,正面的影响不代表对方有多棒,但我希望对方可以肯定我,看得到我身上发光的地方,我也愿意回馈对方同等分量的重视。”
https://blog.csdn.net/weixin_42763696/article/details/108712503
https://www.cnblogs.com/tangjian219/p/11978047.html
网友评论