数据提取2

数据提取之正则

目标:掌握正则表达式的常见语法

​ 掌握re模块的常见语法

​ 掌握原始字符串 r 的用法


1. 什么是正则表达式

用事先定义好的一些特定字符,及这些特定字符的组合,组成一个规则字符串,这个规则字符串用来表达对字符串的一种过滤逻辑

2. 正则表达式的常见语法

知识点:

​ 正则中的字符

​ 正则中的预定义字符集

​ 正则中的数量词


在这里插入图片描述

正则的语法很多,不能够全部复习,对于其他的语法,可以临时查阅资料,比如:表示或还能使用 |

练习:下面的输出是什么?

import re
str1 = '<meta http-equiv="content-type" content="text/html;charset=utf-8"/>adacc/sd/sdef/24'

result = re.findall(r'<.*>', str1)
print(result)

3. re模块的常见方法

pattern.match(从头找一个)

pattern.search(找一个)

pattern.findall(找所有)

贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配

非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配

​ 返回一个列表,没有就是空列表

 re.findall("\d", "aef5teacher2") >>>>  ['5', '2']

pattern.sub(替换)

re.sub("\d", "_", "aef5teacher2") >>>>  ['aef_teacher_']

re.compile(编译)

​ 返回一个模型p,具有和re一样的方法,但是传递的参数不同

​ 匹配模式需要传到compile中

p = re.compile("\d", re.s)
p.findall("aef_teacher")

4. python中原始字符串 r 的用法

定义:所有的字符串都是直接按照字面的意思来使用,没有转义的特殊字符或不能打印的字符,原始字符串往往针对特殊字符而言,例如:“\n"的原始字符串就是”\n"

原始字符串的长度:

len('\n')
# 结果  1
len(r'\n')
# 结果  2
'\n'[0]
# 结果  '\n'
r'\n'[0]
# 结果  '\\'

数据提取之lxml模块与xpath工具

目标:了解xpath的定义

​ 了解lxml

​ 掌握xpath的语法

lxml是一款高新能的python html/xml解析器,我们可以利用xpath,来快速的定位特定元素以及获取节点信息


1. 了解 lxml模块和xpath语法

对html或xml形式的文本提取特定的内容,就需要我们掌握lxml模块的使用和xpath语法。

  • lxml模块可以利用XPath规则语法,来快速的定位HTML\XML 文档中特定元素以及获取节点信息(文本内容、属性值)
  • XPath (XML Path Language) 是一门在 HTML\XML 文档中查找信息的语言,可用来在 HTML\XML 文档中对元素和属性进行遍历
  • 提取xml、html中的数据需要lxml模块和xpath语法配合使用

2. 谷歌浏览器xpath helper插件的安装和使用

要想利用lxml模块提取数据,需要我们掌握xpath语法规则。接下来我们就来了解一下xpath helper插件,它可以帮助我们练习xpath语法**(安装包见课件–工具文件夹)**

  1. 下载Chrome插件 XPath Helper

    • 可以在chrome应用商城进行下载
  2. 将rar压缩包解压到当前文件夹

  3. 打开谷歌浏览器---->右上角三个点---->更多工具---->扩展程序

  4. 在扩展程序界面,点击右上角的开关,进入开发者模式后,将xpath文件夹拖进,释放鼠标即可

  1. 安装完成,校验

3. xpath的节点关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D6IwuiMy-1658853026856)(../img/节点.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lRUWk5Nv-1658853026858)(../img/xpath中节点的关系.png)]

4. xpath语法-基础节点选择语法

  1. XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。
  2. 这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。
  3. 使用chrome插件选择标签时候,选中时,选中的标签会添加属性class=“xh-highlight”

xpath定位节点以及提取属性或文本内容的语法

表达式描述
nodename选中该元素。
/从根节点选取、或者是元素和元素间的过渡。
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
.选取当前节点。
选取当前节点的父节点。
@选取属性。
text()选取文本。

5. xpath语法-节点修饰语法

可以根据标签的属性值、下标等来获取特定的节点

5.1 节点修饰语法

路径表达式结果
//title[@lang=“eng”]选择lang属性值为eng的所有title元素
/bookstore/book[1]选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()]选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1]选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()>1]选择bookstore下面的book元素,从第二个开始选择
//book/title[text()=‘Harry Potter’]选择所有book下的title元素,仅仅选择文本为Harry Potter的title元素
/bookstore/book[price>35.00]/title选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

5.2 关于xpath的下标

  • 在xpath中,第一个元素的位置是1
  • 最后一个元素的位置是last()
  • 倒数第二个是last()-1

6. xpath语法-其他常用节点选择语法

  • // 的用途

    • //a 当前html页面上的所有的a
    • bookstore//book bookstore下的所有的book元素
  • @ 的使用

    • //a/@href 所有的a的href
    • //title[@lang=“eng”] 选择lang=eng的title标签
  • text() 的使用

    • //a/text() 获取所有的a下的文本
    • //a[texts()=‘下一页’] 获取文本为下一页的a标签
    • a//text() a下的所有的文本
  • xpath查找特定的节点

    • //a[1] 选择第一个s
    • //a[last()] 最后一个
    • //a[position()<4] 前三个
  • 包含

    • //a[contains(text(),“下一页”)]选择文本包含下一页三个字的a标签**
    • //a[contains(@class,‘n’)] class包含n的a标签

7. lxml模块的安装与使用示例

lxml模块是一个第三方模块,安装之后使用

7.1 lxml模块的安装

对发送请求获取的xml或html形式的响应内容进行提取

pip/pip3 install lxml

7.2 爬虫对html提取的内容

  • 提取标签中的文本内容
  • 提取标签中的属性的值
    • 比如,提取a标签中href属性的值,获取url,进而继续发起请求

7.3 lxml模块的使用

  1. 导入lxml 的 etree 库

    from lxml import etree

  2. 利用etree.HTML,将html字符串(bytes类型或str类型)转化为Element对象,Element对象具有xpath的方法,返回结果的列表

    html = etree.HTML(text) 
    ret_list = html.xpath("xpath语法规则字符串")
    
  3. xpath方法返回列表的三种情况

    • 返回空列表:根据xpath语法规则字符串,没有定位到任何元素
    • 返回由字符串构成的列表:xpath字符串规则匹配的一定是文本内容或某属性的值
    • 返回由Element对象构成的列表:xpath规则字符串匹配的是标签,列表中的Element对象可以继续进行xpath

lxml模块使用示例

运行下面的代码,查看打印的结果

from lxml import etree
text = ''' 
<div> 
  <ul> 
    <li class="item-1">
      <a href="link1.html">first item</a>
    </li> 
    <li class="item-1">
      <a href="link2.html">second item</a>
    </li> 
    <li class="item-inactive">
      <a href="link3.html">third item</a>
    </li> 
    <li class="item-1">
      <a href="link4.html">fourth item</a>
    </li> 
    <li class="item-0">
      a href="link5.html">fifth item</a>
  </ul> 
</div>
'''

html = etree.HTML(text)

#获取href的列表和title的列表
href_list = html.xpath("//li[@class='item-1']/a/@href")
title_list = html.xpath("//li[@class='item-1']/a/text()")

#组装成字典
for href in href_list:
    item = {}
    item["href"] = href
    item["title"] = title_list[href_list.index(href)]
    print(item)

练习

将下面的html文档字符串中,将每个class为item-1的li标签作为1条新闻数据。提取a标签的文本内容以及链接,组装成一个字典。

text = ''' <div> <ul> 
        <li class="item-1"><a>first item</a></li> 
        <li class="item-1"><a href="link2.html">second item</a></li> 
        <li class="item-inactive"><a href="link3.html">third item</a></li> 
        <li class="item-1"><a href="link4.html">fourth item</a></li> 
        <li class="item-0"><a href="link5.html">fifth item</a> 
        </ul> </div> '''
  • 注意:

    • 先分组,再提取数据,可以避免数据的错乱

    • 对于空值要进行判断

每一组中继续进行数据的提取

 for li in li_list:
      item = {}
      item["href"] = li.xpath("./a/@href")[0] if len(li.xpath("./a/@href"))>0 else None
      item["title"] = li.xpath("./a/text()")[0] if len(li.xpath("./a/text()"))>0 else None
      print(item)
##### 知识点:掌握 lxml模块中使用xpath语法定位元素提取属性值或文本内容
##### lxml模块中etree.tostring函数的使用
####> 运行下边的代码,观察对比html的原字符串和打印输出的结果

from lxml import etree
html_str = ''' <div> <ul> 
      <li class="item-1"><a href="link1.html">first item</a></li> 
      <li class="item-1"><a href="link2.html">second item</a></li> 
      <li class="item-inactive"><a href="link3.html">third item</a></li> 
      <li class="item-1"><a href="link4.html">fourth item</a></li> 
      <li class="item-0"><a href="link5.html">fifth item</a> 
      </ul> </div> '''

html = etree.HTML(html_str)

handeled_html_str = etree.tostring(html).decode()
print(handeled_html_str)

现象和结论

打印结果和原来相比:

  1. 自动补全原本缺失的li标签
  2. 自动补全html等标签
<html><body><div> <ul> 
<li class="item-1"><a href="link1.html">first item</a></li> 
<li class="item-1"><a href="link2.html">second item</a></li> 
<li class="item-inactive"><a href="link3.html">third item</a></li> 
<li class="item-1"><a href="link4.html">fourth item</a></li> 
<li class="item-0"><a href="link5.html">fifth item</a> 
</li></ul> </div> </body></html>

结论

  • lxml.etree.HTML(html_str)可以自动补全标签

  • lxml.etree.tostring函数可以将转换为Element对象再转换回html字符串

  • 爬虫如果使用lxml来提取数据,应该以lxml.etree.tostring的返回结果作为提取数据的依据

课后练习

初步使用

我们利用它来解析 HTML 代码,简单示例:

# lxml_test.py

# 使用 lxml 的 etree 库
from lxml import etree

html = '''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a> # 注意,此处缺少一个 </li> 闭合标签
     </ul>
 </div>
'''

#利用etree.HTML,将字符串解析为HTML文档
xml_doc = etree.HTML(html)

# 按字符串序列化HTML文档
html_doc = etree.tostring(xml_doc)

print(html_doc)

输出结果:

<html><body>
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
 </div>
</body></html>

lxml 可以自动修正 html 代码,例子里不仅补全了 li 标签,还添加了 body,html 标签。

文件读取:

除了直接读取字符串,lxml还支持从文件里读取内容。我们新建一个hello.html文件:

<!-- hello.html -->

<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
     </ul>
 </div>

再利用 etree.parse() 方法来读取文件。

# lxml_parse.py

from lxml import etree

# 读取外部文件 hello.html
html = etree.parse('./hello.html')
result = etree.tostring(html, pretty_print=True)

print(result)

输出结果与之前相同:

<html><body>
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
 </div>
</body></html>

XPath实例测试

1. 获取所有的 <li> 标签
# xpath_li.py

from lxml import etree

xml_doc = etree.parse('hello.html')
print type(html)  # 显示etree.parse() 返回类型

result = xml_doc.xpath('//li')

print result  # 打印<li>标签的元素列表
print len(result)
print type(result)
print type(result[0])

输出结果:

<type 'lxml.etree._ElementTree'>
[<Element li at 0x1014e0e18>, <Element li at 0x1014e0ef0>, <Element li at 0x1014e0f38>, <Element li at 0x1014e0f80>, <Element li at 0x1014e0fc8>]
5
<type 'list'>
<type 'lxml.etree._Element'>
2. 继续获取<li> 标签的所有 class属性
# xpath_li.py

from lxml import etree

html = etree.parse('hello.html')
result = html.xpath('//li/@class')

print result

运行结果

['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
3. 继续获取<li>标签下hreflink1.html<a> 标签
# xpath_li.py

from lxml import etree

html = etree.parse('hello.html')
result = html.xpath('//li/a[@href="link1.html"]')

print result

运行结果

[<Element a at 0x10ffaae18>]
4. 获取<li> 标签下的所有 <span> 标签
# xpath_li.py

from lxml import etree

html = etree.parse('hello.html')

#result = html.xpath('//li/span')
#注意这么写是不对的:
#因为 / 是用来获取子元素的,而 <span> 并不是 <li> 的子元素,所以,要用双斜杠

result = html.xpath('//li//span')

print result

运行结果

[<Element span at 0x10d698e18>]
5. 获取 <li> 标签下的<a>标签里的所有 class
# xpath_li.py

from lxml import etree

html = etree.parse('hello.html')
result = html.xpath('//li/a//@class')

print result

运行结果

['blod']
6. 获取最后一个 <li> 里边的 <a> 的 href属性值
# xpath_li.py

from lxml import etree

html = etree.parse('hello.html')

result = html.xpath('//li[last()]/a/@href')
# 谓语 [last()] 可以找到最后一个元素

print result

运行结果

['link5.html']
7. 获取倒数第二个元素的内容
# xpath_li.py

from lxml import etree

<a href="www.xxx.com">abcd</a>

html = etree.parse('hello.html')
result = html.xpath('//li[last()-1]/a')

# text 方法可以获取元素内容
print result[0].text

运行结果

fourth item
8. 获取 class 值为 bold 的标签名
# xpath_li.py

from lxml import etree

html = etree.parse('hello.html')

result = html.xpath('//*[@class="bold"]')

# tag方法可以获取标签名
print result[0].tag

运行结果

span

数据提取之BeautifuSoup模块与Css选择器(拓展)

"""
# BeautifulSoup
是一个高效的网页解析库,可以从HTML或XML文件中提取数据
支持不同的解析器,比如,对HTML解析,对XML解析,对HTML5解析
就是一个非常强大的工具,爬虫利器
一个灵感又方便的网页解析库,处理高效,支持多种解析器
利用它就不用编写正则表达式也能方便的实现网页信息的抓取
"""

# 安装 pip3 install BeautifulSoup4


# 标签选择器
### 通过标签选择
#### .string() --获取文本节点及内容

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
    <p class="title" name="dromouse"><b><span>The Dormouse's story</span></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>
"""
from bs4 import BeautifulSoup   # 导包
soup = BeautifulSoup(html, 'lxml')  # 参数1:要解析的html  参数2:解析器

# print(soup.prettify())  # 代码补全

print(soup.html.head.title.string)

print(soup.title.string)  #title是个节点, .string是属性 作用是获取字符串文本

# 选取整个head,包含标签本身
print(soup.head) # 包含head标签在内的所有内容

print(soup.p) # 返回匹配的第一个结果


#%% md

### 获取名称
#### .name()  --获取标签本身名称  

#%%

html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')

print(soup.title.name)  # 结果为标签本身  --> title
print(soup.p.name)  # --> 获取标签名

#%% md

### 获取属性值

#### .attrs()  --通过属性拿属性值 

#%%

html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title asdas" name="abc" id = "qwe"><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/123" 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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')

print(soup.p.attrs['name'])# 获取p标签name属性的属性值

print(soup.p.attrs['id']) # 获取p标签id属性的属性值
print(soup.p['id']) #第二种写法

print(soup.p['class']) # 以列表得形式保存
print(soup.a['href'])  # 也是只返回第一个值

#%% md

### 嵌套选择

一定要有子父级关系

#%%

html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The abc 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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.body.p.b.string)  #层层往下找

#%% md

### 子节点和子孙节点

#%%

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')

# 标签选择器只能拿到部分内容 ,不能拿到所有,那如何解决??

# .contents属性可以将tag(标签)的子节点以列表的形式输出
# print(soup.p.contents)  # 获取P标签所有子节点内容 返回一个list

for i in soup.p.contents:
    print(i)


#%%



#%%

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')

# .children是一个list类型的迭代器
print(soup.p.children)  # 获取子节点  返回一个迭代器

for i in soup.p.children:
    print(i)

for i, child in enumerate(soup.p.children):  
    print(i, child)

#%%

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.p.descendants)  # 获取子孙节点  返回一个迭代器
for i, child in enumerate(soup.p.descendants):
    print(i, child)

#%% md

### 父节点和祖先节点

#%%

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.a.parent)  # 获取父节点

#%%

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <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">
                <span>Elsie</span>
            </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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(list(enumerate(soup.a.parents)))  # 获取祖先节点

#%% md

### 兄弟节点

#%%

html = """
<html>
    <head>
        <title>The Dormouse's story</title>
    </head>
    <body>
        <p class="story">
            <span>abcqweasd</span>
            Once upon a time there were three little sisters; and their names were
            <a href="http://example.com/elsie" class="sister" id="link1">
                <span>Elsie</span>
            </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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(list(enumerate(soup.a.next_siblings)))  # 后边的所有的兄弟节点
print('---'*15)
print(list(enumerate(soup.a.previous_siblings))) # 前边的

#%% md

## 实用:标准选择器

#%% md

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

#%% md

可根据标签名、属性、内容查找文档

#%% md

#### 使用find_all根据标签名查找

#%%

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo-2</li>
            <li class="element">Bar-2</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')

print(soup.find_all('ul'))  # 拿到所有ul标签及其里面内容
print(soup.find_all('ul')[0])

ul = soup.find_all('ul')
print(ul) # 拿到整个ul标签及其里面内容
print('____________'*10)

for ul in soup.find_all('ul'):
#     print(ul)  # 遍历ul标签
    for li in ul:
#         print(li)  #遍历li标签
        print(li.string)  # 拿到所有li标签里的文本内容

#%% md

#### 获取文本值

#%%

for ul in soup.find_all('ul'):
    for i in ul.find_all("li"):
        print(i.string)

#%% md

#### 根据属性查找

#%%

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1" name="elements">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')

# 第一种写法 通过attrs
# print(soup.find_all(attrs={'id': 'list-1'})) # 根据id属性
print("-----"*10)
# print(soup.find_all(attrs={'name': 'elements'}))  # 根据name属性

for ul in soup.find_all(attrs={'name': 'elements'}):
    print(ul)  
    print(ul.li.string)  #只能给你返回第一个值
# # # #     print('-----')
    for li in ul:
#         print(li)
        print(li.string)

#%% md

#### 特殊的属性查找  

#%%

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')

# 第二种写法
print(soup.find_all(id='list-1'))
print(soup.find_all(class_='element'))  # class属于Python关键字,做特殊处理 _

# 推荐的查找方法 li标签下的class属性
print(soup.find_all('li',{'class','element'}))  

#%% md

####  根据文本值选择 text

#%%

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')

print(soup.find_all(text='Foo')) # 可以做内容统计用
print(soup.find_all(text='Bar'))
print(len(soup.find_all(text='Foo'))) # 统计数量

#%% md

### find( name , attrs , recursive , text , **kwargs )

#%% md

find返回单个元素,find_all返回所有元素

#%%

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find('ul')) # 只返回匹配到的第一个
print(soup.find('li'))

print(soup.find('page')) # 如果标签不存在返回None

#%% md

### find_parents()  find_parent()

#%% md

find_parents()返回所有祖先节点,find_parent()返回直接父节点。

#%% md

### find_next_siblings()  find_next_sibling()

#%% md

find_next_siblings()返回后面所有兄弟节点,find_next_sibling()返回后面第一个兄弟节点。

#%% md

### find_previous_siblings()  find_previous_sibling()

#%% md

find_previous_siblings()返回前面所有兄弟节点,find_previous_sibling()返回前面第一个兄弟节点。

#%% md

### find_all_next()  find_next()

#%% md

find_all_next()返回节点后所有符合条件的节点, find_next()返回第一个符合条件的节点

#%% md

### find_all_previous() 和 find_previous()

#%% md

find_all_previous()返回节点后所有符合条件的节点, find_previous()返回第一个符合条件的节点

#%% md

## CSS选择器

#%% md

通过select()直接传入CSS选择器即可完成选择

如果对HTML里的CSS选择器很熟悉可以考虑用此方法

#%% md

注意:

    1,写CSS时,标签名不加任何修饰,类名前加. , id名前加# 
    
    2,用到的方法时soup.select(),返回类型是list
    
    3,多个过滤条件需要用空格隔开,从前往后是逐层筛选


#%%

html='''
<div class="pan">q321312321</div>
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')

# 层级 ul li
print(soup.select('ul li'))  # 标签不加任何修饰
print("----"*10)
print(soup.select('.panel .panel-heading')) # 类名前加.
print("----"*10)

print(soup.select('#list-1 .element')) 
print("----"*10)


#%%

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for ul in soup.select('ul'):
    for i in ul.select('li'):
        print(i.string)
        

### 获取属性


html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
# []获取id属性  attrs获取class属性
for ul in soup.select('ul'):
    print(ul['id'])
    print(ul.attrs['class'])


### 获取内容
### get_text()    

html='''
<div class="panel">
    <div class="panel-heading">
        <h4>Hello</h4>
    </div>
    <div class="panel-body">
        <ul class="list" id="list-1">
            <li class="element">Foo</li>
            <li class="element">Bar</li>
            <li class="element">Jay</li>
        </ul>
        <ul class="list list-small" id="list-2">
            <li class="element2">Foo</li>
            <li class="element2">Bar</li>
        </ul>
    </div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for li in soup.select('li'):
    print(li.string)
    print(li.get_text())  # 获取内容

* 推荐使用lxml解析库,必要时使用html.parser
* 标签选择筛选功能弱但是速度快
* 建议使用find()、find_all() 查询匹配单个结果或者多个结果
* 如果对CSS选择器熟悉建议使用select()
* 记住常用的获取属性和文本值的方法

数据提取之CSS选择器

css 语法概要

熟悉前端的同学对 css 选择器一定不会陌生,比如 jquery 中通过各种 css 选择器语法进行 DOM 操作等

数据提取性能比较

在爬虫中使用css选择器,代码教程

>>> from requests_html import session

# 返回一个Response对象
>>> r = session.get('https://python.org/')

# 获取所有链接
>>> r.html.links
{'/users/membership/', '/about/gettingstarted/'}

# 使用css选择器的方式获取某个元素
>>> about = r.html.find('#about')[0]

>>> print(about.text)
About
Applications
Quotes
Getting Started
Help
Python Brochure
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马航行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值