本笔记用于记录整理requests库的一些基本知识,内容会根据博主自己的认知作增添或压缩。
水平有限,如有错误请不吝赐教。
本文需要读者初步了解HTML有关节点的相关知识。
文章目录
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。使用Xpath最初是用于搜寻XML文档的,但同样适用于HTML文档的搜索。
使用Xpath前,请先保证其已经安装,可以利用pip进行安装:
pip3 install lxml
这里主要用到lxml包内的etree的库,其提供了Xpath的方法。
| 表达式 | 描述 |
|---|---|
| nodename | 选取此节点的所有子节点 |
| / | 进入当前节点的直接子节点 |
| // | 进入当前节点的子孙节点 |
| . | 选取当前节点 |
| .. | 选取当前节点的父节点 |
| @ | 选取当前节点的属性 |
小试牛刀:
//title[@endtime="2023-02-04"]
意思是选取所有名为title并带有属性endtime为"2023-02-04"的节点
假设已经存在这样一段HTML文本:
text = '''
<div class="device-notification">
<a class="device-notification--logo" href="#0">
<img src="assets/img/logo.png" alt="Global">
<p>Emoreの云</p>
</a>
<p class="device-notification--message">请将手机横向放置以继续体验</p>
</div>
'''
这意味着这段HTML存在内存内,可能是网上抓取来的或是提前读取好的,接入Xpath的方法如下:
import lxml import etree # 载入etree库
html = etree.HTML(text) # 构造Xpath解析对象
假设有一个text.html文件在你的程序所在的文件夹中,里面这需要解析的HTML文本:
from lxml import etree # 载入etree库
html = etree.parse('./text.html', etree.HTMLParser()) # 从文本构造Xpath解析对象
不论是哪种方法构造Xpath解析对象,etree都会对HTML文本进行修正。如果从文件读取,修正时可能额外出现DOCTYPE声明。
利用Xpath查找结点时,一般采用以//开头的Xpath规则选择所有符合要求的节点。以上文的HTML文本为例:
>>> html = etree.HTML(text)
>>> result1 = html.xpath('//*') # *代表选择当前目录的所有节点
>>> print(result1) # 返回结果是列表
[<Element html at 0x27378d2c440>, <Element body at 0x27378e98140>, <Element div at 0x27378e98300>, <Element a at 0x27378e98400>, <Element img at 0x27378e98440>, <Element p at 0x27378e98480>, <Element p at 0x27378e98240>]
>>> print(result1[0]) # 选取结果中的第一个
<Element html at 0x27378d2c440>
其中Element后面的内容便是节点名,本身不存在的html节点和body节点都自动补全了。
将//后面的内容换成节点名,即可查找指定节点,如查询上文所有的p节点:
>>> result2 = html.xpath('//p')
>>> print(result2)
[<Element p at 0x27378e98480>, <Element p at 0x27378e98240>]
同时可以查询具有指定属性的p节点,只需要在节点名后面附带筛选属性,利用[@]将其包裹起来:
>>> result3 = html.xpath('//p[@class="device-notification--message"]')
>>> print(result3)
[<Element p at 0x27378e98240>]
如此只返回了最后一个p节点。
有的属性不止有一个值(上文HTML并没有这种情况),需要用contains()方法进行匹配。该方法第一个参数为属性名,第二个参数填入属性值,只要拥有该属性值的节点都会被返回。
result = html.xpath('//p[contains(@class, "device-notification--message")]')
需要通过多个属性匹配一个节点,可以利用and进行连接,比如匹配一个class含有值device并且name为Emore的p节点:
result = html.xpath('//p[contains(@class, "device") and @name="Emore"]') # 仅举例
除了and,Xpath还含有很多运算符(摘自菜鸟编程),
| 运算符 | 描述 | 实例 | 返回值 |
|---|---|---|---|
| | | 计算两个节点集 | //book | //cd | 返回所有拥有 book 和 cd 元素的节点集 |
| + | 加法 | 6 + 4 | 10 |
| - | 减法 | 6 - 4 | 2 |
| * | 乘法 | 6 * 4 | 24 |
| div | 除法 | 8 div 4 | 2 |
| = | 等于 | price=9.80 | 如果 price 是 9.80,则返回 true。如果 price 是 9.90,则返回 false。 |
| != | 不等于 | price!=9.80 | 如果 price 是 9.90,则返回 true。如果 price 是 9.80,则返回 false。 |
| < | 小于 | price<9.80 | 如果 price 是 9.00,则返回 true。如果 price 是 9.90,则返回 false。 |
| <= | 小于或等于 | price<=9.80 | 如果 price 是 9.00,则返回 true。如果 price 是 9.90,则返回 false。 |
| > | 大于 | price>9.80 | 如果 price 是 9.90,则返回 true。如果 price 是 9.80,则返回 false。 |
| >= | 大于或等于 | price>=9.80 | 如果 price 是 9.90,则返回 true。如果 price 是 9.70,则返回 false。 |
| or | 或 | price=9.80 or price=9.70 | 如果 price 是 9.80,则返回 true。如果 price 是 9.50,则返回 false。 |
| and | 与 | price>9.00 and price<9.90 | 如果 price 是 9.80,则返回 true。如果 price 是 8.50,则返回 false。 |
| mod | 计算除法的余数 | 5 mod 2 | 1 |
有时候有两个或者多个节点,可以像列表一样选择其中某个节点。需要注意的是,Xpath是从1开始计数的。
# 仅举例
result = html.xpath('//div/p[0]') # 选择第一个p节点
result = html.xpath('//div/p[last()]') # 选择最后一个p节点
result = html.xpath('//div/p[posision()<3]') # 选择前面两个p节点
result = html.xpath('//div/p[last()-2]') # 选择倒数第三个p节点
查找子孙节点只需要像文件路径一样/下去就好了,不同的是/是只访问直接子节点,而//是访问所有的子孙节点:
例如我需要寻找div节点下的p节点:
>>> result4 = html.xpath('//div/p') # 利用'/'搜索节点p
>>> result5 = html.xpath('//div//p') # 利用'//'搜索节点p
>>> print(result4)
[<Element p at 0x27378e98240>]
>>> print(result5)
[<Element p at 0x27378e98480>, <Element p at 0x27378e98240>]
div节点的直接子节点中含有一个p节点,还有一个a节点。其中a节点内含有一个img节点和一个p节点。利用/只检索到一个p节点,而利用//检索到了两个p节点,即访问了子节点和孙节点。
同样类似命令cd ..打开上级目录,Xpath中的..可以用于进入父节点。
>>> result6 = html.xpath('//div/p/../a/img')
>>> print(result6)
[<Element img at 0x27378e98440>]
首先进入了div节点的p节点,然后从p节点返回绕到了a节点,并取得里面的img节点。
利用Xpath内的text()方法可以获得节点的文本,利用@可以获得指定属性的值。
>>> print(result7)
['请将手机横向放置以继续体验']
>>> result8 = html.xpath('//div/p/@class')
>>> print(result8)
['device-notification--message']
同样输出为列表。
通过轴节点可以快速选择具有相关关系的节点,如选择div节点的所有直接子节点:
>>> result10 = html.xpath('//div/child::*')
>>> print(result10)
[<Element a at 0x27378e98400>, <Element p at 0x27378e98240>]
首先需要调用child轴,获得所有匹配的节点,然后使用两个冒号::进入选择器,接着用*选择所有节点。
还有很多轴可供选择(摘自菜鸟编程):
| 轴名称 | 结果 |
|---|---|
| ancestor | 选取当前节点的所有先辈(父、祖父等)。 |
| ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。 |
| attribute | 选取当前节点的所有属性。 |
| child | 选取当前节点的所有子元素。 |
| descendant | 选取当前节点的所有后代元素(子、孙等)。 |
| descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
| following | 选取文档中当前节点的结束标签之后的所有节点。 |
| following-sibling | 选取当前节点之后的所有兄弟节点 |
| namespace | 选取当前节点的所有命名空间节点。 |
| parent | 选取当前节点的父节点。 |
| preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
| preceding-sibling | 选取当前节点之前的所有同级节点。 |
| self | 选取当前节点。 |
使用XPath可以快速而准确地进行HTML节点选择,并提取信息,但是要注意构造XPath表达式,以避免提取错误。
同时还有一些需要注意的地方:
text()会返回错误的文本,如一个换行符或一个缩进。我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。
我正在学习http://ruby.railstutorial.org/chapters/static-pages上的RubyonRails教程并遇到以下错误StaticPagesHomepageshouldhavethecontent'SampleApp'Failure/Error:page.shouldhave_content('SampleApp')Capybara::ElementNotFound:Unabletofindxpath"/html"#(eval):2:in`text'#./spec/requests/static_pages_spec.rb:7:in`(root)'
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt