自学内容网 自学内容网

2024 高级爬虫笔记(一)bs4和xpath使用教程

一、数据解析利器——beautifulsoup

1.1 安装

pip install beautifulsoup4

1.2 安装解析器

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则 Python 会使用 Python默认的解析器,lxml 解析器更加强大,速度更快,推荐安装。
安装方式:python pip install lxml

1.3 快速使用:

# 导入bs
from bs4 import BeautifulSoup
# 初始化bs对象,html_doc为解析文本,'lxml'为解析器
soup = BeautifulSoup(html_doc, 'lxml')
# 对html进行美化
print(soup.prettify())

# 获取第一个title标签
soup.title  

soup.title.name   # 获取标签名称

soup.title.string   # 获取标签title内的内容

soup.title.parent  # 获取父级标签

soup.title.parent.name  # 获取父级标签名称

soup.p    # 获取第一个p标签

soup.p['class']  # 获取p的class属性值

soup.a    # 获取第一个a标签

soup.find_all('a')    # 获取所有a标签

soup.find(id="link3")  # 获取id为link3的标签

1.4 获取标签内容相关方法:

1.4.1 .content、.strings和.text

1.4.1.1 相同点与区别:
.content、.strings和.text方法都可以返回标签内所有的文本内容,区别在于.content返回列表,.strings返回生成器,.text返回字符串
1.4.1.2 使用示例:
# 获取第一个head标签
head_tag = soup.head

# 获取head标签下所有子标签的内容
head_tag.contents
head_tag.strings
head_tag.text

for string in soup.strings:
    print(repr(string))

# 获取第一个子标签的内容
title_tag = head_tag.contents[0]

1.4.2 .string

1.4.2.1 使用场景:
如果标签里面没有标签了,那么 .string 就会返回标签里面的内容。
如果标签里面只有唯一的一个标签了,那么 .string 也会返回最里面的内容。
如果标签里面包含了多个子标签,.string 的输出结果是 None

1.4.3 .stripped_strings

1.4.3.1 使用场景:
输出的字符串中可能包含了很多空格或空行,使用 `.stripped_strings`可以去除多余空白内容

for string in soup.stripped_strings:
    print(repr(string))

1.5 搜索相关方法:

1.5.1 find_all方法

1.5.1.1 使用场景及示例:
`find_all()` 方法搜索当前标签的所有子标签,并判断是否符合过滤器的条件

# 搜索所有title标签
soup.find_all("title")

# 搜索所有class为title的p标签
soup.find_all("p", "title")

# 搜索所有a标签
soup.find_all("a")

# 搜索所有id为link2的标签
soup.find_all(id="link2")

# 使用正则匹配
import re
# 模糊查询所有文本内容包含sisters的标签
soup.find_all(string=re.compile("sisters"))
1.5.1.2 传入参数解析:
1、name参数解析:
    `name` 参数可以查找所有名字为 `name` 的标签,字符串对象会被自动忽略掉
    `name` 参数的值可以是字符串,正则表达式,列表,方法或是 `True`
    传入字符串:
        最简单的过滤器是字符串.在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容
        下面的例子用于查找文档中所有的<b>标签:
            soup.find_all('b')
    
    传入正则表达式:
        如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 `match()` 来匹配内容.
        下面例子中找出所有以b开头的标签,这表示\<body>和\<b>标签都应该被找到:
            import re
            for tag in soup.find_all(re.compile("^b")):
                print(tag.name)

    传列表:
        如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回
        下面代码找到文档中所有\<a>标签和\<b>标签:
            soup.find_all(["a", "b"])

2、keyword 参数解析:
    如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索
    比如如果包含一个名字为 `id` 的参数,Beautiful Soup会搜索每个标签的”id”属性:
        soup.find_all(id='link2')
    
    其他示例:
        import re
        # 超链接包含elsie标签
        print(soup.find_all(href=re.compile("elsie")))

        # 以The作为开头的字符串
        print(soup.find_all(text=re.compile("^The")))

    使用多个指定名字的参数可以同时过滤tag的多个属性:
        soup.find_all(href=re.compile("elsie"), id='link1')

    如果我们想用 class 过滤,不过 class 是 python 的关键词,需要加个下划线:
        print(soup.find_all("a", class_="sister"))

3、attrs 参数解析:
    通过`attrs` 参数定义一个字典参数来搜索包含特殊属性的tag:
        data_soup.find_all(attrs={"data-foo": "value"})

    注意:如何查看条件idclass同时存在时的写法
        print(soup.find_all('b', class_="story", id="x"))
        print(soup.find_all('b', attrs={"class":"story", "id":"x"}))

4、text 参数解析:
    通过 `text` 参数可以搜搜文档中的字符串内容:
        # 只要包含Dormouse就可以
        print(soup.find_all(text=re.compile("Dormouse")))

5、limit 参数解析:
    `find_all()` 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢
    如果我们不需要全部结果,可以使用 `limit` 参数限制返回结果的数量:
        print(soup.find_all("a",limit=2))

1.6 css选择器

1、通过标签名查找
    print(soup.select("title"))  
    print(soup.select("b"))      

2、通过类名查找
    print(soup.select(".sister"))

3、通过id名查找
    print(soup.select("#link1"))

4、组合查找
    组合查找和写 class 文件时,标签名与类名、id名进行的组合原理是一样的
    例如查找 p 标签中,id 等于 link1的内容,二者需要用空格分开
    print(soup.select("p #link2"))

5、直接子标签查找
    print(soup.select("p > #link2"))

6、查找既有class也有id选择器的标签
    a_string = soup.select(".story#test")

7、查找有多个class选择器的标签
    a_string = soup.select(".story.test")

8、查找有多个class选择器和一个id选择器的标签
    a_string = soup.select(".story.test#book")

9、属性查找
    查找时还可以加入属性元素,属性需要用中括号括起来
    注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。
    print(soup.select("a[href='http://example.com/tillie']"))

10、select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容:
    for title in soup.select('a'):
        print (title.get_text())

二、数据解析利器——xpath

2.1、xpath安装 pip install lxml

2.2、快速使用

  # 解析网络的html字符串
  html_tree = etree.HTML(html字符串)
  html_tree.xpath()
  使用xpath路径查询信息,返回一个列表

2.3、xpath语法

2.3.1、路径表达式:

  | /    | 从根节点选取。                       |
  | //   | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
  | ./   | 当前节点再次进行xpath                 |
  | @    | 选取属性。                         |

  在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:
  | /html               | 选取根元素。 |
  | //li                | 选取所有li 子元素,而不管它们在文档中的位置。                |
  | //ul//li            | 选择属于 ul元素的后代的所有 li元素,而不管它们位于 ul之下的什么位置。  |
  | 节点对象.xpath('./div') | 选择当前节点对象里面的第一个div节点                      |
  | //@href             | 选取名为 href 的所有属性。                         |

2.3.2、谓语(Predicates):

  谓语用来查找某个特定的节点或者包含某个指定的值的节点。
  谓语被嵌在方括号中。

  在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
  | 路径表达式                              | 结果                                       |
  | /ul/li[1]                          | 选取属于 ul子元素的第一个 li元素。                     |
  | /ul/li[last()]                     | 选取属于 ul子元素的最后一个 li元素。                    |
  | /ul/li[last()-1]                   | 选取属于 ul子元素的倒数第二个 li元素。                   |
  | //ul/li[position()<3]              | 选取最前面的两个属于 ul元素的子元素的 li元素。               |
  | //a[@title]                        | 选取所有拥有名为 title的属性的 a元素。                  |
  | //a[@title='xx']                   | 选取所有 a元素,且这些元素拥有值为 xx的 title属性。          |
  | //a[@title>10]   `> < >= <= !=`    | 选取 a元素的所有 title元素,且其中的 title元素的值须大于 10|
  | /bookstore/book[price>35.00]/title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00|

2.3.3、选取未知节点:

  XPath 通配符可用来选取未知的 XML 元素。
  | 通配符    | 描述                              |
  | *      | 匹配任何元素节点。  一般用于浏览器copy xpath会出现 |
  | @*     | 匹配任何属性节点。                       |
  | node() | 匹配任何类型的节点。                      |

  在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
  | 路径表达式       | 结果                  |
  | /ul/*       | 选取 ul元素的所有子元素。      |
  | //*         | 选取文档中的所有元素。         |
  | //title[@*] | 选取所有带有属性的 title 元素。 |
  | //node()    | 获取所有节点              |

2.3.4、选取若干路径:

  通过在路径表达式中使用“|”运算符,您可以选取若干个路径。

  在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
  | 路径表达式                            | 结果                                       |
  | //book/title | //book/price     | 选取 book 元素的所有 title 和 price 元素。          |
  | //title | //price               | 选取文档中的所有 title 和 price 元素。               |
  | /bookstore/book/title | //price | 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。 |

2.3.5、逻辑运算

  查找所有id属性等于head并且class属性等于s_down的div标签
    //div[@id="head" and @class="s_down"]

  选取文档中的所有 title 和 price 元素。
   //title | //price

  注意:|”两边必须是完整的xpath路径

2.3.6、属性查询

  查找所有包含id属性的div节点
    //div[@id]

  查找所有id属性等于maincontent的div标签
   //div[@id="maincontent"]

  查找所有的class属性
   //@class
   
  获取li标签中name为xx的里面的文本内容
   //li[@name="xx"]//text()  

2.3.7、查询相关

  查询所有id属性中包含he的div标签
    //div[contains(@id, "he")]

  查询所有id属性中包以he开头的div标签
   //div[starts-with(@id, "he")]

  查找所有div标签下的直接子节点h1的内容
  //div/h1/text()

2.3.8、获取节点内容转换成字符串

  c = tree.xpath('//li/a')[0]
  result=etree.tostring(c, encoding='utf-8')
  print(result.decode('UTF-8'))

原文地址:https://blog.csdn.net/qq_40652101/article/details/142490135

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!