数据解析-Xpath

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标签

    1. 提取数据
    • 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容