Python3网络爬虫(五) -- 爬虫解析库LXML、BeautifulSoup、PyQuery

解析库会按照层次来提取,所以效率会大大的提升

PyQuery:强大好用

1. 字符串初始化

html = 一段网页源代码
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('li'))

选择所有的li节点

2. URL初始化:

from pyquery import PyQuery as pq
doc = pq(url='http://cuiqingcai.com')
print(doc('title'))

传递的参数不仅可以是字符串,还可以是网页的URL,他会先请求这个URL,然后使用得到的HTML初始化,它相当于下面代码:

from pyquery import PyQuery as pq
import requests
doc = pq(requests.get('http://cuiqingcai.com').text)
print(doc('title'))

3. 文件初始化:
传入文件名,直接初始化里面的HTML

from pyquery import PyQuery as pq
doc = pq(filename='demo.html')
print(doc('li'))

4. CSS选择器:

from pyquery import PyQuery as pq
doc = pq(html)
print(doc('#container .list li'))

选取ID为container的节点内部的class为list的节点内部的所有li标签节点

5. 查找节点:
首先有:

from pyquery import PyQuery as pq
doc = pq(html)
items = doc('.list')

返回的结果基本上都是PyQuery类型!!!!

  • 所有子孙节点find: lis = items.find('li') 结果类型不是list,而是pyquery
  • 直接子节点children: lis = items.children()
  • 符合条件的直接子节点:lis = items.children('.active') 可传入css选择器
  • 直接父节点parent: container = items.parent()
  • 祖先父节点parents: parent = items.parents('.wrap')
  • 兄弟节点siblings: print(li.siblings())

6. 遍历:
根据上面的查找节点方法,我们可以发现,PyQuery选择出来的节点可能是单个也可能是多个,类型也都是PyQuery类型而不是beautifulsoup那样的列表,那么我们需要遍历这个特殊类型:

from pyquery import PyQuery as pq
doc = pq(html)
lis = doc('li').items()
print(type(lis))
for li in lis:
    print(li, type(li))

items()函数会得到一个生成器,遍历一下就可以得到li标签节点了。

7. 获取信息
我们现在已经找到了特定节点,现在我们就需要获取节点的特定信息:
a = doc('.item-0.active a')

  • 获取属性: print(a.attr('href'))或者print(a.attr.href),当选中多个节点的时候,attr只会返回第一个节点的属性,所以需要用到遍历
  • 获取纯文字文本: print(a.text()) 会忽略掉节点内包含的所有HTML,只返回纯的文字内容
  • 获取HTML文本: print(li.html()) 返回节点内的所有HTML文本
  • 当选中多个节点的时候,html()返回的是第一个节点的内部HTML文本,但是text()返回了所有节点的内部纯文本,中间用一个空格分割,实际上总体是一个字符串。

8. 节点操作
PyQuery有方法可以动态的修改节点,这样会对提取信息带来极大的遍历。
li = doc('.item-0.active') 首先选取了单个节点

  • 增加移除class:li.removeClass('active')li.addClass('active')
  • 修改属性: li.attr('name', 'link') 将name属性改为link
  • 修改纯文本内容: li.text('changed item')
  • 修改HTML内容: li.html('<span>changed item</span>')

移除remove(): 这个会为筛选信息提供极大的帮助!!!!
例子:

html = '''
<div class="wrap">
    Hello, World
    <p>This is a paragraph.</p>
 </div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
wrap = doc('.wrap')
print(wrap.text())

我们这样使用的text()方法会返回Hello, World This is a paragraph. 这个结果包含了内部的p节点内容,因为text()会把所有的纯文本全部提取,这个时候我们可以:
wrap.find('p').remove()
直接去掉里面的p标签节点

9. 伪类选择器:
伪类选择器可以选择第一个节点,最后一个节点,奇偶数节点,包含某一文本的节点等等

  • 第一个节点: li = doc('li:first-child')
  • 最后一个节点: li = doc('li:last-child')
  • 第二个li节点: li = doc('li:nth-child(2)')
  • 偶数位置的节点: li = doc('li:nth-child(2n)')
  • 包含特殊文本的节点: li = doc('li:contains(second)')


BeautifulSoup

BeautifulSoup 是 Python 的一个 HTML 或 XML 的解析库,我们可以用它来方便地从网页中提取数据。 BeautifulSoup 在解析的时候实际上是依赖于解析器的,它除了支持 Python 标准库中的 HTML 解析器,还支持一些第三方的解析器比如 LXML,推荐使用LXML解析库,因为它能解析HTML和XML:

BeautifulSoup(markup, "lxml")  # 解析HTML
BeautifulSoup(markup, "xml")  # 解析XML

例子:

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')  # 会自动更正HTML里面未闭合的错误
print(soup.prettify())  # 将要解析的字符串以标准的缩进格式输出
print(soup.title.string)  # 选中节点然后输出文本
# 这样选择title只会选择第一个匹配到的节点

1. 方法选择器!!!推荐使用

最常用的查询方法莫过于 find_all() 和 find() 了
find_all():
find_all(name , attrs , recursive , text , **kwargs)

  • 根据名字查询:
    print(soup.find_all(name='ul'))
    可以继续遍历:
for ul in soup.find_all(name='ul'):
    print(ul.find_all(name='li'))
    for li in ul.find_all(name='li'):
        print(li.string)
  • 根据属性查询:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(attrs={'id': 'list-1'}))
print(soup.find_all(attrs={'name': 'elements'}))

对于特殊的id和class,我们有更方便的方法查询:

print(soup.find_all(id='list-1'))
print(soup.find_all(class_='element'))     

这里注意class在python里面是一个关键字,所以需要在后面加一个下划线

  • 根据文本关键字查询
    匹配的可以是字符串也可以是正则表达式对象:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(text=re.compile('link')))

结果会返回所有匹配正则表达式的节点文本组成的列表

find():
该方法返回单个元素,也就是第一个匹配的元素

还有一些其他方法:
find_parents() 返回所有祖先节点
find_parent() 返回直接父节点

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

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

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

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




!!!!上面是推荐使用方法,下面是介绍一下其他方法!!!!!!!












2.节点选择器 X不推荐使用X:

获取节点名称:
print(soup.title.name)

获取节点属性:

print(soup.p.attrs)  # 返回字典结构,所有属性
print(soup.p.attrs['name'])
print(soup.p['name'])  # 简易写法
print(soup.p['class'])  # 如果想获取Class,会返回一个列表,因为一个节点有可能有多个class

获取节点内容:
print(soup.p.string)

嵌套选择:
print(soup.head.title.string)
可以在一个节点的基础上再选择节点

关联选择:
子节点:
使用contents属性可以得到一个列表形式的直接子节点,如果里面既包含文本,也包含节点,返回结果都将以列表的形式统一返回,

使用children属性也可以得到结果

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.p.children)
for i, child in enumerate(soup.p.children):
    print(i, child)

返回的结果一样,只不过该属性返回的是生成器类型,而contents返回的是列表类型

子孙节点:

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.p.descendants)
for i, child in enumerate(soup.p.descendants):
    print(i, child)

父节点:
使用parent属性可以获取节点的直接父节点:
print(soup.a.parent)

祖父节点:
使用parents属性可以获取所有的祖先节点:
list(enumerate(soup.a.parents))
返回结果是一个生成器类型,上面代码用列表输出了它的索引和内容

兄弟节点:

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print('Next Sibling', soup.a.next_sibling)
print('Prev Sibling', soup.a.previous_sibling)
print('Next Siblings', list(enumerate(soup.a.next_siblings)))  # 返回生成器
print('Prev Siblings', list(enumerate(soup.a.previous_siblings)))  # 返回生成器

3. CSS选择器

使用 CSS 选择器,只需要调用 select() 方法,传入相应的 CSS 选择器即可,这里不多做介绍,因为如果要使用CSS选择器,推荐使用PyQuery!!!

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))
print(type(soup.select('ul')[0]))


XPath(LXML):

首先先安装LXML库

常用规则:

表达式用法
nodename选取此节点的所有子节点
/从当前节点选取直接子节点
//从当前节点选取子孙节点
.选取当前节点
选取当前节点的父节点
@选取属性

例子://title[@lang=’eng’] 表示所有标签为title,并且lang属性为eng的节点
例子:

from lxml import etree
html = etree.HTML(text)  # 要么将文本用HTML类初始化
html = etree.parse('./test.html', etree.HTMLParser())  # 要么直接对文本文件进行解析
result = etree.tostring(html)
print(result.decode('utf-8'))

result = html.xpath('//*')  # 返回了所有节点列表

result = html.xpath('//li/a')  # 选择 li 节点下的所有直接 a 子节点

result = html.xpath('//a[@href="link4.html"]/../@class')  # 首先选中href为特定东西的a节点,然后选取它的父节点,在得到它的class属性。

result = html.xpath('//li[@class="item-0"]/text()')  # text()方法可以获取节点的文本

result = html.xpath('//li/a/@href')  # 获取li节点下所有a节点的href属性

属性多值匹配:
result = html.xpath('//li[contains(@class, "li")]/a/text()')
通过contains()方法,第一个参数为属性名称,第二个为属性值,只要属性包含这个传入的属性值就可以匹配

**多属性匹配:**from bs4 import BeautifulSoup
soup = BeautifulSoup(html, ‘lxml’)
print(soup.select(’.panel .panel-heading’))
print(soup.select(‘ul li’))
print(soup.select(’#list-2 .element’))
print(type(soup.select(‘ul’)[0]))
result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
使用运算符来连接

按序选择节点:

result = html.xpath('//li[1]/a/text()')  # 选择第一个li节点,这里是从1开始计数!!!

result = html.xpath('//li[last()]/a/text()')  # 选取最后一个节点

result = html.xpath('//li[position()<3]/a/text()')  # 选择位置小于三的节点,也就是1和2

result = html.xpath('//li[last()-2]/a/text()')  # 选取倒数第三个节点

使用节点轴选择节点:

result = html.xpath('//li[1]/ancestor::*')
# 使用了ancestor轴,获取所有的祖先节点,后面需要跟着两个冒号,后面才是节点选择器,使用了*代表匹配所有节点

result = html.xpath('//li[1]/ancestor::div')
# 加上限定条件,只返回div这个祖先节点

result = html.xpath('//li[1]/attribute::*')
# 使用attribute轴,获取所有属性,两个冒号后面是*即获取所有属性,所以最后返回第一个li的所有属性

result = html.xpath('//li[1]/child::a[@href="link1.html"]')
# 使用child轴,获取所有子节点

result = html.xpath('//li[1]/descendant::span')
#  使用descendant轴,获取所有的子孙节点

result = html.xpath('//li[1]/following::*[2]')
#  使用了following轴,可以获取所有的后续节点,虽然使用了*匹配所有,但是后面紧跟

result = html.xpath('//li[1]/following-sibling::*')
# 使用了following-sibling轴,可以获取当前节点之后的所有同级节点,加上*匹配,即所有后续同级节点
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值