网页元素定位

Xpath、bs4和jsonpath

正则、xpath、beautifulsoup、jsonpath都是在爬虫爬取数据时,定位数据的不同规则方法。为什么不写正则?因为正则太简单了,知道元字符怎么使用,记住match、search和find就可以了。为什么写jsonpath,因为某网站的数据都可以使用jsonpath来获取,所以整理一些知识点让大家了解一下子。

一、Xpath

安装:pip install lxml

使用:

1、需要导入相关模块 from lxml import etree;
2、然后加载解析文件 html = etree.HTML(“html_code”)

知识点1:根据标签中的属性去匹配数据,使用格式为 [@属性=”属性值”],一般用作寻找下一级或者匹配其他相同数据但不好匹配的内容;

知识点2:使用text() 获取文本,如果没有text,那么结果则打印出一个对象;

song = html.xpath('//li[@class="songlist__header_name"]/text()')

知识点3:使用@获取属性中的值,常见的会有获取a中的href链接和img中的src图片地址;当然也可以获取你想要的属性的值;

songurl = html.xpath('//div[@class="songlist__artist"]/a/@href')

知识点4:同时获取两个不同标签中的内容,比如招聘网站中的“职位介绍”和“职位要求”,需要同时获取到可以使用 ‘|’;

title2 = html.xpath('//i/@title | //div/@title')

知识点5:在xpath语句中获取相同标签下指定索引的数据时使用 [索引] ,xpath中的索引从1开始;

syz = html.xpath('//ul[@class="songlist__header"]//li[1]/text()')

知识点6:position() 此方法可以通过各种比较运算获取相关的值

pos = html.xpath('//ul[@class="songlist__list"]//li[position()<=2]//a[@class="js_song"]/text()')

完整代码示例:

# 导入相关模块
from lxml import etree
# 加载解析文件
html = etree.HTML(html_code)
# 获取 歌曲
# 知识点1:指定标签下的属性获取数据时,格式为 [@属性=“属性值”]  此时打印会得到一个对象
# 知识点2:/text() 获取文本song = html.xpath('//li[@class="songlist__header_name"]/text()')
# print(song)
# 获取歌曲详情url
# 知识点3:获取标签中属性的属性值使用@ ,如下:
songurl = html.xpath('//div[@class="songlist__artist"]/a/@href')
# print(songurl)
# 知识点4:同时获取数据,使用 |  如下获取标签i中的title值和div中的title值
title2 = html.xpath('//i/@title | //div/@title')
# print(title2)
# 知识点5:获取相同标签下指定索引的数据 使用[索引],xpath中的索引从1开始
syz = html.xpath('//ul[@class="songlist__header"]//li[1]/text()')
# print(syz)
# 知识点6:使用position对比查找指定索引   这里大于2,则结果为第3个pos = html.xpath('//ul[@class="songlist__list"]//li[position()<=2]//a[@class="js_song"]/text()')
print(pos)

二、Beautifulsoup

安装:pip install bs4

使用:

1、导入该模块 from bs4 import Beautiful
2、创建一个对象,指定解析类型soup = BeautifulSoup(html,'lxml')

知识点0:bs4中有id选择器div#id和class选择器div.class,请根据自己的需求和实际情况进行使用;

知识点1:使用.text 或者 .string 获取文本;

知识点2:select()方法返回列表,所以可以直接使用 [索引] 获取想要的数据;

texta2 = soup.select('div.text > a')[2].text

知识点3:使用.get()方法来获取属性值,比如a标签的href和img的src;

urla = soup.select('[class="text"] > a')[2].get('href')

知识点4:find()匹配一个,find_all()匹配所有,find_xxx还有很多方法,详细的内容可以查看代码中的注释或官方手册;

atags = soup.find_all('a')

知识点5:^ 显示开头;$ 限制结尾;*模糊查询;

kt = soup.select('span[class^="t"]')

完整代码示例

from bs4 import BeautifulSoup 
soup = BeautifulSoup(html,'lxml') 
# 获取标题(直接 .标签.text(或.string)获取指定数据的文本信息) 
title = soup.title.string 46# print(title) 
#  获取 
#资信评估
# 超链接及文本 
''' 
selece()  返回值为列表,
如果获取一个,使用select_one,类似于xpath在scrapy中的.extrace_first();
如果获取每一个,请遍历;如果找其中的某个数据,请添加索引,此处用法同xpath
# 知识点1:获取文本使用.text 
# 知识点2:获取任意属性的属性值,如href,scr 使用.get() 53# 知识点3:依次获取下一层标签使用 > 
''' 
texta1 = soup.select('div[class="text"] > a')[2].text texta2 = soup.select('div.text > a')[2].text
# print(texta)
# 也可以直接用属性,不加标签,建议添加 urla = soup.select('[class="text"] > a')[2].get('href') 
# print(urla)
# 子孙级 去查找相关属性的标签
zisun = soup.select('p .text-blue') 
# print(zisun)
# 子级 直接查找属性的标签 
zi = soup.select('p > .text-blue') 
# print(zi)
# ^ 查询所有以t开头的标签(类似正则的限制开头) 
kt = soup.select('span[class^="t"]')
# print(kt) 
# $ 查询所有以t结尾的标签(类似正则中限制结尾) 
jw = soup.select('span[class$="t"]') 
# print(jw) 
# * 模糊查询 
mh = soup.select('span[class*="u"]') 
# print(mh) 
# 获取span标签的单个属性(首个)
attr = soup.span['class'] 
# print(attr) 
# 以字典的格式输出属性及属性值 
attrs = soup.span.attrs 
# print(attrs)
# 上面多用class选择器获取数据,格式: .classattr (.+class属性值) 
# bs4中还有id选择器,格式: #idattr (#+id属性值) 
idele = soup.select('div#sub-li') 
# print(idele) 
# 获取代码中所有a标签  find_all()   结果返回列表 
atags = soup.find_all('a') 
# for a in atags: 
# 打印a标签 包含其中的内容
#     print(a)
#     # 打印标签名
#     print(a.name)
#     # 获取链接文本   下面两种都可以使用
#     print(a.text)
#     print(a.get_text())
# 只匹配第一个标签
aele = soup.find('a')
# print(aele)
# 在bs4中,True可以作为参数匹配所有标签,如下:
tags = soup.find_all(True)
# for tag in tags:
#     print(tag.name)
# 获取所有含有 target 属性的内容  可以使用除class属性之外的所有属性,因为python中class是关键字
targets = soup.find_all(target=True)
# print(targets)
'''
其他补充:
# 1.string作为参数时,可以查找指定的数据,string中的参数都会被打印,可以是单个字符串也可以是列表
# 一定要区别 .string 
strword = soup.find_all(string = ['风控','律师'])
print(strword)
# 2.limit 用来限制输出数量,如下,只输出两个a标签的内容
resnum = soup.find_all('a',limit=2)
print(resnum)
# 3.find_parents() 和 find_parent() 用来查找父节点,如下
# 寻找父级,需要反向查询,find_parents返回列表
fu = soup.find(string = '律师')
ua = fu.find_parent('a')
print(ua)
# 4. find_next() 解析下一个对象   find_previous() 解析上一个对象
'''
'''
# 扩展1138139diagnose()可以检测使用lxml 还是 xml进行解析,使用diagnose(),需要导入相关模块 from bs4.diagnose import diagnose
bs4默认将文档作为html进行解析,如果需要xml,请将BeautifulSoup()第二个参数改为xml,如soup = BeautifulSoup(html,'lxml')
'''
# from bs4.diagnose import diagnose
# # 直接使用该函数即可# diagnose(html)
'''
# 扩展2  了解即可
xml  解析xml格式如网站地图的sitemap.xml
lxml 解析html网页
html5lib  容错性较好,以浏览器的方式解析文档,生成h5格式的文档     并不常用
# 扩展3 157中文官方手册:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
'''

三、Jsonpath

Jsonpath可以理解为匹配解析json的xpath

安装:pip install jsonpath

使用:

1、导入模块 import jsonpath
2、使用jsonpath.jsonpath(jsoncode,’rules’)格式进行匹配

知识点1:$表示根元素,必须要有,和xpath起始处的/一样;

allele = jsonpath.jsonpath(jscode,'$..*')

知识点2:*表示所有

name = jsonpath.jsonpath(jscode,'$.data.comments[*]..name')

知识点3:[索引] jsonpath语法中的索引从0开始;

digg_count = jsonpath.jsonpath(jscode,'$.data.comments[0].digg_count')

知识点4:?() 表示指定数据,过滤出自己选择的内容 @表示指定的对象

elelist = jsonpath.jsonpath(jscode,'$..comments[?(@.zgl)]')

知识点5:jsonpath中比较运算的使用

reply_count = jsonpath.jsonpath(jscode,'$..comments[?(@.reply_count>3)]')

知识点6:获取最后一个数据,也可以使用切片的形式(见完整代码)

lone = jsonpath.jsonpath(jscode,'$..comments[(@.length-1)]')

完整代码示例:

# 输出所有数据内容 
allele = jsonpath.jsonpath(jscode,'$..*') 
# print(allele)
# 获取commonets中所有用户名 name name = jsonpath.jsonpath(jscode,'$.data.comments[*]..name') # print(name) 
# 获取点赞数 digg_count = jsonpath.jsonpath(jscode,'$.data.comments[0].digg_count') # print(digg_count)
# 获取用户id 如果没有指定索引,则获取所有并返回列表 
# 可以指定索引得出结果,如[2]获取第三个数据,也可以将所有user_id_list进行遍历 user_id_list = jsonpath.jsonpath(jscode,'$..user.user_id') print(user_id_list) 
# [2:10:2] [start:end:step] [开始索引:结束索引:间隔步长]  如下,从索引2开始到10,间隔为2输出
# 类似python中的切片 user_id = jsonpath.jsonpath(jscode,'$..user.user_id')[2:10:2] # print(user_id)
# user中的所有数据  * 表示所有alluser = jsonpath.jsonpath(jscode,'$..user.*')
# print(alluser)
# 包含zgl的数据  ?() 表示指定数据,过滤出自己选择的内容  @表示指定的对象
elelist = jsonpath.jsonpath(jscode,'$..comments[?(@.zgl)]')
# for ele in elelist:
#     print(ele['zgl'])
# 获取回复大于3的数据   < > = 等相关的用法  大家可以自己修改数据进行测试
reply_count = jsonpath.jsonpath(jscode,'$..comments[?(@.reply_count>3)]')
# print(reply_count)
#  最后一个数据
# lone = jsonpath.jsonpath(jscode,'$..comments[(@.length-1)]')
lone = jsonpath.jsonpath(jscode,'$..comments[-1:]')
print(lone)
'''
xpath中开头/表示根路径,jsonpath中$表示根路径;
xpath语句中/表示子级,jsonpath中.和[]表示子级;
xpath中..表示父级,使用//表示子孙级,jsonpath中..表示子孙级
xpath中()表示分组,jsonpath中()表示
*在xpath和jsonpath中一样,都表示所有
'''
# http://jsonpath.herokuapp.com/   测试jsonpath的在线网站

无论是哪一种定位匹配数据的方法,都需要大量的练习,熟能生巧才能游刃有余。

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

推荐阅读更多精彩内容