首页 > 其他分享 >一步一步学爬虫(3)网页解析之parsel的使用

一步一步学爬虫(3)网页解析之parsel的使用

时间:2023-01-05 14:36:48浏览次数:40  
标签:提取 一步 text 爬虫 Selector item parsel selector

(一步一步学爬虫(3)网页解析之parsel的使用)

3.4 parsel的使用

  前文我们了解了 lxml 使用 XPath 和 pyquery 使用 CSS Selector 来提取页面内容的方法,不论是 XPath 还是 CSS Selector,对于绝大多数的内容提取都足够了,大家可以选择适合自己的库来做内容提取。

  不过这时候有人可能会问:我能不能二者穿插使用呀?有时候做内容提取的时候觉得 XPath 写起来比较方便,有时候觉得 CSS Selector 写起来比较方便,能不能二者结合起来使用呢?答案是可以的。

  这里我们就介绍另一个解析库,叫做 parsel。

  注意:如果你用过 Scrapy 框架(后文会介绍)的话,你会发现 parsel 的 API 和 Scrapy 选择器的 API 极其相似,这是因为 Scrapy 的选择器就是基于 parsel 做了二次封装,因此学会了这个库的用法,后文 Scrapy 选择器的用法就融会贯通了。

3.3.1 介绍

  parsel 这个库可以对 HTML 和 XML 进行解析,并支持使用 XPath 和 CSS Selector 对内容进行提取和修改,同时它还融合了正则表达式提取的功能。功能灵活而又强大,同时它也是 Python 最流行爬虫框架 Scrapy 的底层支持。

3.3.2 准备工作

  在本节开始之前,请确保已经安装好了 parsel 库,如尚未安装,可以使用 pip3 进行安装即可:

pip3 install parsel   更详细的安装说明可以参考:https://setup.scrape.center/parsel。

  安装好之后,我们便可以开始本节的学习了。

3.3.3 初始化

  首先我们还是用上一节的示例 HTML,声明 html 变量如下:

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

  接着,一般我们会用 parsel 的 Selector 这个类来声明一个 Selector 对象,写法如下:

from parsel import Selector
selector = Selector(text=html)

  这里我们创建了一个 Selector 对象,传入了 text 参数,内容就是刚才声明的 HTML 字符串,赋值为 selector 变量。

  有了 Selector 对象之后,我们可以使用 css 和 xpath 方法分别传入 CSS Selector 和 XPath 进行内容的提取,比如这里我们提取 class 包含 item-0 的节点,写法如下:

items = selector.css('.item-0')
print(len(items), type(items), items)
items2 = selector.xpath('//li[contains(@class, "item-0")]')
print(len(items2), type(items), items2)

  我们先用 css 方法进行了节点提取,输出了提取结果的长度和内容,xpath 方法也是一样的写法,运行结果如下:

3 <class 'parsel.selector.SelectorList'> [<Selector xpath="descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' item-0 ')]" data='<li class="item-0">first item</li>'>, <Selector xpath="descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' item-0 ')]" data='<li class="item-0 active"><a rel="nofollow" href="li...'>, <Selector xpath="descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' item-0 ')]" data='<li class="item-0"><a rel="nofollow" href="link5.htm...'>]
3 <class 'parsel.selector.SelectorList'> [<Selector xpath='//li[contains(@class, "item-0")]' data='<li class="item-0">first item</li>'>, <Selector xpath='//li[contains(@class, "item-0")]' data='<li class="item-0 active"><a rel="nofollow" href="li...'>, <Selector xpath='//li[contains(@class, "item-0")]' data='<li class="item-0"><a rel="nofollow" href="link5.htm...'>]

  可以看到两个结果都是 SelectorList 对象,它其实是一个可迭代对象。另外可以用 len 方法获取它的长度,都是 3,提取结果代表的节点其实也是一样的,都是第 1、3、5 个 li 节点,每个节点还是以 Selector 对象的形式返回了,其中每个 Selector 对象的 data 属性里面包含了提取节点的 HTML 代码。

  不过这里可能大家有个疑问,第一次我们不是用 css 方法来提取的节点吗?为什么结果中的 Selector 对象还输出了 xpath 属性而不是 css 属性呢?这是因为 css 方法背后,我们传入的 CSS Selector 首先被转成了 XPath,XPath 才真正被用作节点提取。其中 CSS Selector 转换为 XPath 这个过程是在底层用 cssselect 这个库实现的,比如 .item-0 这个 CSS Selector 转换为 XPath 的结果就是 descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' item-0 ')],因此输出的 Selector 对象有了 xpath 属性了。不过这个大家不用担心,这个对提取结果是没有影响的,仅仅是换了一个表示方法而已。

3.3.4 提取文本

  好,既然刚才提取的结果是一个可迭代对象 SelectorList,那么要获取提取到的所有 li 节点的文本内容就要对结果进行遍历了,写法如下:

from parsel import Selector
selector = Selector(text=html)
items = selector.css('.item-0')
for item in items:
    text = item.xpath('.//text()').get()
    print(text)

  这里我们遍历了 items 变量,赋值为 item,那么这里 item 又变成了一个 Selector 对象,那么此时我们又可以调用其 css 或 xpath 方法进行内容提取了,比如这里我们就用 .//text() 这个 XPath 写法提取了当前节点的所有内容,此时如果不再调用其他方法,其返回结果应该依然为 Selector 构成的可迭代对象 SelectorList。SelectorList 有一个get 方法,get 方法可以将 SelectorList 包含的 Selector 对象中的内容提取出来。

  运行结果如下:

first item
third item
fifth item

  这里 get 方法的作用是从 SelectorList 里面提取第一个 Selector 对象,然后输出其中的结果。

  我们再看一个实例:

result = selector.xpath('//li[contains(@class, "item-0")]//text()').get()
print(result)

输出结果如下:

first item

  其实这里我们使用 //li[contains(@class, "item-0")]//text() 选取了所有 class 包含 item-0 的 li 节点的文本内容。应该来说,返回结果 SelectorList 应该对应三个 li 对象,而这里 get 方法仅仅返回了第一个 li 对象的文本内容,因为其实它会只提取第一个 Selector 对象的结果。

  那有没有能提取所有 Selector 的对应内容的方法呢?有,那就是 getall 方法。

  所以如果要提取所有对应的 li 节点的文本内容的话,写法可以改写为如下内容:

result = selector.xpath('//li[contains(@class, "item-0")]//text()').getall()
print(result)

  输出结果如下:

['first item', 'third item', 'fifth item']

  这时候,我们就能得到列表类型结果了,和 Selector 对象是一一对应的。

  因此,如果要提取 SelectorList 里面对应的结果,可以使用 get 或 getall 方法,前者会获取第一个 Selector 对象里面的内容,后者会依次获取每个 Selector 对象对应的结果。

  另外上述案例中,xpath 方法改写成 css 方法,可以这么实现:

result = selector.css('.item-0 *::text').getall()
print(result)

  这里 * 用来提取所有子节点(包括纯文本节点),提取文本需要再加上::text,最终的运行结果是一样的。

  到这里我们就简单了解了文本提取的方法。

3.3.5 提取属性

  刚才我们演示了 HTML 中文本的提取,直接在 XPath 中加入 //text() 即可,那提取属性怎么做呢?类似的方式,也直接在 XPath 或者 CSS Selector 中表示出来就好了。

  比如我们提取第三个 li 节点内部的 a 节点的 href 属性,写法如下:

from parsel import Selector
selector = Selector(text=html)
result = selector.css('.item-0.active a::attr(href)').get()
print(result)
result = selector.xpath('//li[contains(@class, "item-0") and contains(@class, "active")]/a/@href').get()
print(result)

  这里我们实现了两种写法,分别用 css 和 xpath 方法实现。我们根据同时包含 item-0 和 active 这两个 class 为依据来选取第三个 li 节点,然后进一步选取了里面的 a 节点,对于 CSS Selector,选取属性需要加 ::attr() 并传入对应的属性名称来选取,对于 XPath,直接用 /@ 再加属性名称即可选取。最后统一用 get 方法提取结果即可。

  运行结果如下:

link3.html
link3.html

  可以看到两种方法都正确提取到了对应的 href 属性。

3.3.6 正则提取

  除了常用的 css 和 xpath 方法,Selector 对象还提供了正则表达式提取方法,我们用一个实例来了解下:

from parsel import Selector
selector = Selector(text=html)
result = selector.css('.item-0').re('link.*')
print(result)

  这里我们先用 css 方法提取了所有 class 包含 item-0 的节点,然后使用 re 方法,传入了 link.*,用来匹配包含 link 的所有结果。

  运行结果如下:

['link3.html"><span class="bold">third item</span></a></li>', 'link5.html">fifth item</a></li>']

  可以看到,re 方法在这里遍历了所有提取到的 Selector 对象,然后根据传入的正则表达式查找出符合规则的节点源码并以列表的形式返回。

  当然如果在调用 css 方法时已经提取了进一步的结果,比如提取了节点文本值,那么 re 方法就只会针对节点文本值进行提取:

from parsel import Selector
selector = Selector(text=html)
result = selector.css('.item-0 *::text').re('.*item')
print(result)

  运行结果如下:

['first item', 'third item', 'fifth item']

  另外我们也可以利用 re_first 方法来提取第一个符合规则的结果:

from parsel import Selector
selector = Selector(text=html)
result = selector.css('.item-0').re_first('<span class="bold">(.*?)</span>')
print(result)

  这里调用了 re_first 方法,这里提取的是被 span 标签包含的文本值,提取结果用小括号括起来表示一个提取分组,最后输出的结果就是小括号部分对应的结果,运行结果如下:

third item

  通过这几个例子我们知道了正则匹配的一些使用方法,re 对应多个结果,re_first 对应单个结果,可以在不同情况下选择对应的方法进行提取。

3.3.7总结

  parsel 是一个融合了 XPath、CSS Selector 和正则表达式的提取库,功能强大又灵活,建议好好学习一下,同时也可以为后文学习 Scrapy 框架打下基础,有关 parsel 更多的用法可以参考其官方文档:https://parsel.readthedocs.io/。

标签:提取,一步,text,爬虫,Selector,item,parsel,selector
From: https://blog.51cto.com/u_15930659/5991050

相关文章

  • 一步一步学爬虫(4)数据存储之文本存储
    (一步一步学爬虫(4)数据存储之文本存储)4.1TXT纯文本文件存储  将数据保存到TXT文本的操作非常简单,而且TXT文本几乎兼容任何平台,但是这有个缺点,那就是不利于检索。所......
  • 一步一步学爬虫(4)数据存储之JSON存储
    (一步一步学爬虫(4)数据存储之JSON存储)4.2方便灵活的JSON文本文件存储  JSON,全称为JavaScriptObjectNotation,也就是JavaScript对象标记,它通过对象和数组的组合......
  • 一步一步学爬虫(4)数据存储之CSV文件存储
    (一步一步学爬虫(4)数据存储之CSV文件存储)4.3CSV文件存储CSV,全称Comma-SeparatedValues,中文叫做逗号分隔值或字符分隔值,其文件以纯文本形式存储表格数据。CSV文件是一个......
  • 一步一步学爬虫(1)爬虫概念
    (一步一步学爬虫(1)爬虫概念)第1章爬虫概念概念网络爬虫也叫网络蜘蛛,特指一类自动批量下载网络资源的程序,这是一个比较口语化的定义。更加专业和全面对的定义是:网络爬......
  • 一步一步学爬虫(2)基本库的使用之urllib
    (一步一步学爬虫(2)基本库的使用之urllib)2.1urllib的使用Pythonurllib库用于操作网页URL,并对网页的内容进行抓取处理。urllib包包含以下几个模块:urllib.request......
  • 一步一步学爬虫(2)基本库的使用之requests
    (一步一步学爬虫(2)基本库的使用之requests)2.2requests的使用2.2.1准备工作requests库的安装pip3installrequests2.2.2实例引入importrequestsr=requests.......
  • python爬虫之抓取高清壁纸
    对于很多电脑玩家喜欢给自己电脑装饰精美的壁纸,但是碍于图片大小清晰度等原因无法找到合适的,今天我就利用爬虫技术手段,现实高清壁纸抓取,需要的小伙伴可以一起过来看看!#cod......
  • Python爬虫常用哪些库?
    经常游弋在互联网爬虫行业的程序员来说,如何快速的实现程序自动化,高效化都是自身技术的一种沉淀的结果,那么使用Python爬虫都会需要那些数据库支持?下文就是有关于我经常使用的......
  • 【K哥爬虫普法】大数据风控第一案:从魔蝎科技案件判决,看爬虫技术刑事边界
    我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K哥特设了“K哥爬虫普法”专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的......
  • Python爬虫知识点之模块作用
    上一篇文中我们用到了Python的几个模块做了百度新闻的爬取,这些模块他们在爬虫中的作用如下:1、requests模块它用来做http网络请求,下载URL内容,相比Python自带的urllib.reque......