xpath基本知识

XPath语法:使用路径表达式来选取XML或HTML文档中的节点或节点集

路径表达式

nodename:表示选取此节点的所有子节点

/    : 表示从根节点选取

//   :选择任意位置的某个节点。

           .  :选取当前节点

          ..   :选取当前节点的父节点

@   :选取属性

   谓语实例

实现效果                                                                 路劲表达式

选取属于classroom子元素的第一个student元素              /classroom/student[1]

选取属于classroom子元素的最后一个student元素            /classroom/student[last()]

选取属于classroom子元素的倒数第二个stduent元素         /classroom/stduent[last()-1]

选取最前面的两个属于classroom元素的子元素的student元素  /classroom/stduent[position()<3]

选取所有拥有名为lang的属性的name元素                                //name[@lang]

选取所有name元素,且这些元素拥有值为eng的lang属性   //name[@lang='en']

选取classroom元素的所有student元素,且其中的age元素的值须大于20   .classroom.stduent[age>20]

选取classroom元素中的student元素的所有name元素,且其中的age元素的值须大于20   /classroom/stduent[age>20]/name

通配符“*”与“|”操作

实现效果                                                    路径表达式

选取classroom元素的所有子元素                      /classroom/*

选取文档中的所有元素                                       //*

选取所有带有属性的name元素                          //name[@*]

选取stduent元素的所有name和age元素           //stduent/name | //stduent/age

选取属于classroom元素的student元素的所有name元素,以及文档中所有的age元素             /classroom/stduent/name | //age

  XPath轴                  步的语法为   轴名称:节点测试[谓语]

             轴名称                                                           含义

            child                                           选取当前节点的所有子节点

parent                                            选取当前节点的父节点

ancestor                                          选取当前节点的所有先辈(父、祖父等)

ancestor-or-self                      选取当前节点的所有先辈以及当前节点本身

descendant                          选取当前节点的所有后代节点

descendant-or-self              选取当前节点的所有后代节点以及当前节点本身

preceding                            选取文档中当前节点的开始标记之前的所有节点

following                                选取文档中当前节点的结束标记之后的所有节点

preceding-sibling      选取当前节点之前的所有同级节点

following-sibling           选取当前节点之后的所用同级节点

self                                 选取当前节点

attribute                          选取当前节点的所有属性

namespace                选取当前节点的所有命名空间

XPath轴示例分析

实现效果                                                                          路径表达式

选取当前classroom节点中子元素的teacher节点                            /classroom/child::teacher

选取所有id节点的父节点                                                                  //id/parent::*

选取所有以classid为子节点的祖先节点                                             //classid/ancestor::*

选取classroom节点下的所有后代节点                                               /classroom/descendant::*

选取所有以student为父节点的id元素                                             //student/descendant::id

选取所有classid元素的祖先节点及本身                                             //classid/ancestor-or-self::*

选择/classroom/student本身及其所有后代元素                    /classroom/student/descendant-or-self::*

选取/classroom/teacher之前的所有同级节点,结果就是选所有的student节点   /classroom/teacher/preceding-sibling::*

选取/classroom中第二个stduent之后的所有同级节点            /classroom/student[2]/following-sibling::*

选取/classroom/teacher节点所有之前的节点(除其祖先外),不仅仅是student节点,还有里面的子节点  /classroom/teacher/preceding::*

选取/classroom中第二个student之后的所有节点,结果就是选择了teacher节点及其子节点    /classroom/student[2]/following::*

选取student节点,单独使用没有什么意思            //stduent/self::*

选取/classroom/teacher/name节点下的所有属性        /classroom/teacher/name/attribute::*

XPath运算符示例分析

含义                                                                                                       实例

选取classroom元素的所有student元素                   /classroom/student[age=19+1]      /classroom/stduent[age=5*4]   /classroom/student[age=21-1]

且其中的age元素的值须等于20                                                 /classroom/student[age=40div2]

类似可以选取  大于、小于、不等于等操作

or   运算实例        /classroom/stduent[age<20 or age>25]                             .................age小于20或者大于25

and 运算实例        /classroom/stduent[age>20 and age<25]                           ..................age在20 到25 之间

mod  计算除法的余数

实例代码

  1. from lxml import etree
  2.  
  3. contentStream = open(r'xpathText.xml', 'rb')
  4. content = contentStream.read().decode('utf-8')
  5. root = etree.XML(content)
  6. print(content)
  7. print('-------')
  8. em = root.xpath('/classroom/student[2]/following::*')
  9. print(em[0].xpath('./name/text()'))#获取name标签中文本的内容
  10. print(em[0].xpath('./name/@lang')) #获取name标签中属性名为lang的属性值

BeautifulSoup基础知识

创建BeautifulSoup对象的两种方式   1.通过字符串创建     soup=BeautifulSoup(htl_str,'lxml')  其中'lxml'表示指定的解析方式

2.通过文件创建  soup=BeautifulSoup(open('index.html'))

对象种类  四种  Tag、NavigableString、BeautifulSoup 、Comment

1)Tag

在html中每个标签及其里面的内容就是一个Tag对象,如何抽取Tag呢?

soup.title抽取title     soup.a 抽取a  利用soup+标记名查找的是再内容中第一个符合要求的标记

Tag中有两个最重要的属性:name和attributes.每个Tag都有自己的名字,通过.name来获取

修改Tag的name,修改完成后将影响所有通过当前Beautiful Soup对象生成的HTML文档

html_str = """<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>"""
soup = BeautifulSoup(html_str, 'lxml')
# soup = BeautifulSoup(open(r'index.html','rb'),'lxml')
print(soup.prettify()) #以格式化的形式输出文档的内容
print(soup.name)
print(soup.title.name)#输出title的名称
soup.title.name = 'mytitle' #修改title的名称为mytitle
print(soup.title) #title已经修改输出None
print(soup.mytitle)#输出mytitle Tag

输出结果

  1. 整个文档的内容
  2. [document]
  3. title
  4. None
  5. <mytitle>The Dormouse's story</mytitle>

获取Tag属性?<p class="title"><b>The Dormouse's story</b></p>Tag p中有一个属性class值为title,获取代码如下:

Tag属性值的修改类似于上述标签名的修改    soup.p['class']='myclass' 就把属性值title改为了myclass

  1. # 获取Tag中的属性 和字典类似
  2. print(soup.p['class'])
  3. print(soup.p.get('class'))

输出结果

  1. ['title']
  2. ['title']

用于获取Tag所有属性的方法  print(soup.p.attrs)以字典的行书获取指定Tag的所有属性:属性值字典

输出格式如下

  1. {'class': ['title']}

2)NavigableString     当已经得到了标记的内容,要想获取标记的内部文字怎么办呢?需要用到.string。

  1. print(soup.b.string)#输出Tag对象b的内容
  2. print(type(soup.b.string))#输出Tage对象b的内容的类型 其实就是NavigableString类型

输出结果

  1. The Dormouse's story
  2. <class 'bs4.element.NavigableString'>

3)Beautiful Soup

Beautiful Soup对象表示的是一个文档的全部内容。大部分时候,可以把它当作Tag对象,是一个特殊的人Tag,实例如下

  1. print(type(soup.name))
  2. print(soup.name)
  3. print(soup.attrs)

输出结果

  1. <class 'str'>
  2. [document]
  3. {}

4) Comment  文档的注释部分 ,示例如下

  1. print(soup.a.string)
  2. print(type(soup.a.string))

输出结果

  1. Elsie
  2. <class 'bs4.element.Comment'>

遍历文档

               1)子节点

  Tag中的.contents和.children是非常重要的,都是输出直接子节点,Tag的contents属性可以将Tag子节点以列表的方式输出:

  1. print(soup.html.contents)
  2. print(soup.html.contents[1])#如果soup.html.contents[1].string会直接输出文档里的内容,具体解释看下面

输出结果

  1. ['\n', <head><mytitle>The Dormouse's story</mytitle></head>, '\n', <body>
  2. <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
  3. <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
  4. <a class="sister" href="http://example.com/lacie" id="link2">
  5. <!--Lacie -->
  6. </a>
  7. and
  8. <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
  9. and they lived at the bottom of a well.
  10. </p><p class="story">……</p>
  11. </body>, '\n']
  12. <head><mytitle>The Dormouse's story</mytitle></head>

Tag中children,其实.children返回的是一个生成器,可以对Tag的子节点进行循环

  1. for child in soup.html.children: # 孩子结点递归循环
  2. print(child)

输出结果:对于输出换行时,他要空两行,因为print自带换行

  1. <head><mytitle>The Dormouse's story</mytitle></head>
  2.  
  3. <body>
  4. <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
  5. <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
  6. <a class="sister" href="http://example.com/lacie" id="link2">
  7. <!--Lacie -->
  8. </a>
  9. and
  10. <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
  11. and they lived at the bottom of a well.
  12. </p><p class="story">……</p>
  13. </body>

.descendants属性可以对所有tag的子孙节点进行递归循环:head中只有一个直接2节点title,但title也包含一个子节点:字符串'The Dormouse's story',

在这种情况下,字符串也属于<head>标记的子孙节点,

  1. for child in soup.head.descendants: # 子孙节点递归循环
  2. print(child)

输出结果

  1. <mytitle>The Dormouse's story</mytitle>
  2. The Dormouse's story

如何获取标记的内容呢???这就涉及.string、.strings、stripped_strings三个属性

.string这个属性很有特点:如果一个标记里面没有标记了,那么.string就会返回标记里面的内容。如果标记里面只有唯一

的一个标记了,那么.string也会返回最里面的内容。如果tag包含多个子节点,tag就无法确定,string方法应该调用哪个子节点的内容,.string的输出结果是None

  1. print(soup.head.string)
  2. print(soup.mytitle.string)
  3. print(soup.html.string)

输出结果

  1. The Dormouse's story
  2. The Dormouse's story
  3. None

.strings属性主要应用于tag中包含多个字符串的情况,可以进行循环遍历

  1. for stri in soup.strings:
  2. print(repr(stri))

输出结果

  1. '\n'
  2. "The Dormouse's story"
  3. '\n'
  4. '\n'
  5. "The Dormouse's story"
  6. 'Once upon a time there were three little sisters; and their names were\n '
  7. '\n'
  8. '\n'
  9. '\n'
  10. '\n and\n '
  11. 'Tillie'
  12. ';\n and they lived at the bottom of a well.\n'
  13. '……'
  14. '\n'
  15. '\n'

.stripped_strings属性可以去掉输出字符串中包含的空格或换行,示例如下

  1. for stri in soup.stripped_strings:
  2. print(repr(stri))

输出结果

  1. "The Dormouse's story"
  2. "The Dormouse's story"
  3. 'Once upon a time there were three little sisters; and their names were'
  4. 'and'
  5. 'Tillie'
  6. ';\n and they lived at the bottom of a well.'
  7. '……'

2)父节点

每个Tag或者字符串都有父节点:被包含在某个Tag中。通过.parent可以获取某个元素的父节点

print soup.mytitle.parent  输出<head><title>........</title></head>

通过元素的.parents属性可以递归得到元素所有父辈节点,使用.parents方法遍历了<a>标记到根节点的所有节点

  1. print(soup.a)
  2. for parent in soup.a.parents:
  3. if parent is None:
  4. print(parent)
  5. else:
  6. print(parent.name)

输出结果

  1. <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
  2. p
  3. body
  4. html
  5. [document]

3)兄弟节点:可以理解为和本节点出在同一级上的节点,.next_sibling属性可以获取该节点的下一个兄弟节点,.previous_sibling则与之相反,

如果节点不存在,则返回None

可以通过.next_siblings和.previous_siblings来迭代所有的兄弟节点 

4)前后节点

前后节点需要使用.next_element、previous_element这两个属性,他针对所有节点,不分层次,例如<head><title>The Dormouse‘s story</title></head>

中的下一个节点是title

如果想遍历所有的前节点或者后节点,通过.next_elements和previous_elements的迭代器就可以向前或向后访问文档的解析内容

  1. for elem in soup.html.next_elements: #有点像深度优先遍历
  2. print(repr(elem))

输出结果

  1. '\n'
  2. <head><mytitle>The Dormouse's story</mytitle></head>
  3. <mytitle>The Dormouse's story</mytitle>
  4. "The Dormouse's story"
  5. '\n'
  6. <body>
  7. <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
  8. <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
  9. <a class="sister" href="http://example.com/lacie" id="link2">
  10. <!--Lacie -->
  11. </a>
  12. and
  13. <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
  14. and they lived at the bottom of a well.
  15. </p><p class="story">……</p>
  16. </body>
  17. '\n'
  18. <p class="title"><b>The Dormouse's story</b></p>
  19. <b>The Dormouse's story</b>
  20. "The Dormouse's story"
  21. <p class="story">Once upon a time there were three little sisters; and their names were
  22. <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
  23. <a class="sister" href="http://example.com/lacie" id="link2">
  24. <!--Lacie -->
  25. </a>
  26. and
  27. <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
  28. and they lived at the bottom of a well.
  29. </p>
  30. 'Once upon a time there were three little sisters; and their names were\n '
  31. <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
  32. ' Elsie '
  33. '\n'
  34. <a class="sister" href="http://example.com/lacie" id="link2">
  35. <!--Lacie -->
  36. </a>
  37. '\n'
  38. 'Lacie '
  39. '\n'
  40. '\n and\n '
  41. <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
  42. 'Tillie'
  43. ';\n and they lived at the bottom of a well.\n'
  44. <p class="story">……</p>
  45. '……'
  46. '\n'
  47. '\n'

搜索文档

   只介绍find_all()方法,其它方法类似

函数原型

find_all(name,attrs,recursive,text,**kwargs)

1)name参数

name参数可以查找所有名字为name的标记,字符对象会被自动忽略掉。name参数取值可以是字符串、正则表达式、列表、True和方法

字符串案例 用于查找文档中所有的<b>标记  ,返回值为列表:

  1. print(soup.find_all('b'))
  2. #输出结果
  3. [<b>The Dormouse's story</b>]

传入正则表达式作为参数,会通过正则表达式的match()来匹配内容。下面列出所有以b开头的标记,这表示<body>和<b>标记

  1. for tag in soup.find_all(re.compile('^b')):
  2. print(tag.name)
  3. #输出结果
  4. body
  5. b

传入列表

print(soup.find_all(['a','b']))//找到文档中所有的<a>标记和<b>标记

传入True,True可以匹配任何值,会查找所有的tag ,但不会返回字符串节点

  1. for tag in soup.find_all(True):
  2. print(tag.name)
  3. #输出结果
  4. html
  5. head
  6. mytitle
  7. body
  8. p
  9. b
  10. p
  11. a
  12. a
  13. a
  14. p

如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数Tag节点,如果这个方法返回?True表示当前元素匹配并且被找到

,如果不是则返回False,比如过滤包含class属性,也包含id属性的元素

  1. def hasClass_Id(tag):
  2. return tag.has_attr('class') and tag.has_attr('id')
  3. print(soup.find_all(hasClass_Id))
  4. #输出结果
  5. [<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">
  6. <!--Lacie -->
  7. </a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

2)kwargs参数

kwargs参数就是python中的keyword参数 ,如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字Tag的属性来搜索

。搜索指定名字的属性时可以使用的参数值包括字符串、正则表达式、列表、True

传入字符串   print(soup.find_all(id='link2'))  会搜索每个tag的id属性

传入正则表达式    print(soup.find_all(href=re.compile('elsie')))搜索href属性中含有‘elsie’的tag

True         print(soup.find_all(id=True))  文档树中查找所有包含id属性的Tag,无论id的值是什么:

如果想用 class过滤·,但class是python的关键字,需要在class后main加个下划线:

soup.find_all('a',class_='sister')

有些tag属性在搜索中不能使用,比如HTML5中的data-*属性   可以通过find_all()方法的attrs参数定义一个字典参数来搜索包含特殊属性的tag

  1. data_soup = BeautifulSoup('<div data-foo="value">foo!</div>', 'lxml')
  2. print(data_soup.find_all(attrs={"data-foo": "value"}))
  3. # data_soup.find_all(data - foo = 'value') #报错 特殊属性不能这样处理
  4. #输出结果
  5. [<div data-foo="value">foo!</div>]

3)text参数

通过text参数可以搜索文档中的字符串内容。与name参数的可选值一样,text参数接受字符、正则表达式、列表、True

print soup.find_all(text=["Tillie", "Elsie", "Lacie"])
print soup.find_all(text=re.compile("Dormouse"))输出结果

[u'Elsie', u'Lacie', u'Tillie']
[u"The Dormouse's story", u"The Dormouse's story"]

4)limit参数

find_all()方法返回全部的搜索结构,如果文档树很大那么搜索会很慢2.如果我们不需要全部结果,可以使用limit参数限制返回结果的数量

soup.find_all('a',limit=2)值返回两条结果

5)recursive参数

调用tag的find_all()方法是,Beautiful Soup会检索当前tag的所有子孙节点,如果只想检索tag的直接子节点,可以使用参数

recusive=False

  1. print(soup.find_all('mytitle'))
  2. print(soup.find_all('mytitle', recursive=False))
  3. #输出结果
  4. [<mytitle>The Dormouse's story</mytitle>]
  5. []

Python中xPath技术和BeautifulSoup的使用的更多相关文章

  1. 第14.9节 Python中使用urllib.request+BeautifulSoup获取url访问的基本信息

    利用urllib.request读取url文档的内容并使用BeautifulSoup解析后,可以通过一些基本的BeautifulSoup对象输出html文档的基本信息.以博文<第14.6节 使用 ...

  2. 第14.8节 Python中使用BeautifulSoup加载HTML报文

    一. 引言 BeautifulSoup是一个三方模块bs4中提供的进行HTML解析的类,可以认为是一个HTML解析工具箱,对HTML报文中的标签具有比较好的容错识别功能.阅读本节需要了解html相关的 ...

  3. 关于爬虫中常见的两个网页解析工具的分析 —— lxml / xpath 与 bs4 / BeautifulSoup

    http://www.cnblogs.com/binye-typing/p/6656595.html 读者可能会奇怪我标题怎么理成这个鬼样子,主要是单单写 lxml 与 bs4 这两个 py 模块名可 ...

  4. 在Python中使用BeautifulSoup进行网页爬取

    目录 什么是网页抓取? 为什么我们要从互联网上抓取数据? 网站采集合法吗? HTTP请求/响应模型 创建网络爬虫 步骤1:浏览并检查网站/网页 步骤2:创建用户代理 步骤3:导入请求库 检查状态码 步 ...

  5. 在C#中实现Python的分片技术

    在C#中实现Python的分片技术 前言 之前在学习Python的时候发现Python中的分片技术超好玩的,本人也是正则表达式热爱狂,平时用C#比较多,所以决定把Python中的分片技术在C#中实现, ...

  6. python中的线程技术

    #!/user/bin/env python # @Time :2018/7/7 11:42 # @Author :PGIDYSQ #@File :DaemonTest.py import threa ...

  7. Python中第三方的用于解析HTML的库:BeautifulSoup

    背景 在Python去写爬虫,网页解析等过程中,比如: 如何用Python,C#等语言去实现抓取静态网页+抓取动态网页+模拟登陆网站 常常需要涉及到HTML等网页的解析. 当然,对于简单的HTML中内 ...

  8. python中使用XPath笔记

    XPath在Python的爬虫学习中,起着举足轻重的地位,对比正则表达式 re两者可以完成同样的工作,实现的功能也差不多,但XPath明显比re具有优势,在网页分析上使re退居二线. XPath介绍: ...

  9. xpath技术,用在dom4j中

    title: xPath语法应用 tags: xPath,dom4j grammar_cjkRuby: true --- 在dom4j中,会使用到xPath技术. 在项目中导入 jaxen-1.1-b ...

随机推荐

  1. Codeforces Round #525 (Div. 2)D. Ehab and another another xor problem

    D. Ehab and another another xor problem 题目链接:https://codeforces.com/contest/1088/problem/D Descripti ...

  2. linux内存条排查

    已发现2个内存错误,应用名称(kernel:),日志内容(hangzhou-jishuan-DDS0248 kernel: sbridge: HANDLING MCE MEMORY ERROR han ...

  3. APP本地服务安全测试

    一.安全测试基本分类: 1.系统安全 系统加固 安全加固:比如linux中关闭telnet端口,修改ssh端口 检测一些不必要的服务(需要卸载一个ping)--保证系统的最小集 app安全加固:加一层 ...

  4. maven2应用之jar插件使用介绍

    [转载声明] 转载时必须标注:本文来源于铁木箱子的博客http://www.mzone.cc [本文地址] 本文永久地址是:http://www.mzone.cc/article/236.html 有 ...

  5. 最大流算法 ISAP 模板 和 Dinic模板

    ISAP // UVa11248 Frequency Hopping:使用ISAP算法,加优化 // Rujia Liu struct Edge { int from, to, cap, flow; ...

  6. linux基础(2)

    Linux基础题 作业一:1) 新建用户natasha,uid为1000,gid为555,备注信息为“master”useradd natashagroupmod -g 555 natashauser ...

  7. windows支持applocker的版本

    Operating system requirements   The following table show the on which operating systems AppLocker fe ...

  8. 内置函数补充,__str__方法、__del__方法 和 __call__方法和元祖

    一 .内置函数补充 1.isinstance函数: isinstance(obj,cls)检查obj是否是类 cls 的对象 使用该函数来判断一个函数的类型 2. issubclass(sub, su ...

  9. python3,判断,循环练习1

    1.使用while循环输出1 2 3 4 5 6 8 9 10 i = 1 while i <= 10: if i == 7: i += 1 print(end=' ') continue pr ...

  10. mac air 装ubuntu16.04

    前言 我的mac air购于14年,128GB款.最开始我只是在OS X系统里留出了70GB给ubuntu,然后通过u盘装了ubuntu 14.04,后来又陆续将系统升级到15.04.16.04.各方 ...