爬虫基础之pyquery

爬虫程序中少不了解析库的使用,使用库来解析网页内容的话,效率会很高,常用的解析库有:

  • lxml
  • Beautiful Soup
  • pyquery

十里对三个库都稍微了解了一下,个人比较喜欢pyquery库,当然这只是个人喜好问题,无关优劣。所以本文中十里将与您一起学习pyquery库的简单使用。

安装

安装很简单,这里使用pip包管理工具安装:

pip3 install pyquery

注: pip有时会很慢,可以使用国内源加速,这个需要的话自行google。

使用

初始化内容

pyquery库可以打开本地html文件,可以初始化字符串,同样可以直接打开指定网址。

初始化字符串

可以编写一个html字符串内容传给PyQuery,直接看代码:

from pyquery import PyQuery as pq

html = '''<html>
<div>
<p class='ppp'>hello, 5km!</p>
</div>
</html>
'''

d = pq(html)
print(d)
print(type(d))

运行结果:

<html>
<div>
<p class="ppp">hello, 5km!</p>
</div>
</html>
<class 'pyquery.pyquery.PyQuery'>

初始化文件

将上述代码中的html内容写入文件5km.html,然后按照以下方式可以初始化html文件:

from pyquery import PyQuery as pq

d = pq(filename='5km.html')
print(d)
print(type(d))

执行代码后会发现结果与上述一样,说明成功初始化。

初始化链接

这里以http://www.httpbin.org为例:

from pyquery import PyQuery as pq

d = pq(url='http://www.httpbin.org')
print(d)
print(type(d))

结果就会返回上述网址对应的html文件内容:

<html lang="en">
<head>
  <meta charset="UTF-8"/>
  <title>httpbin.org</title>
  <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet"/>
...这里省略部分内容
...
</html>
<class 'pyquery.pyquery.PyQuery'>

CSS选择器

pyquery支持基本的css选择器,可以按照css选择器的规则找到相应节点,为了方便展示后面的使用,从这儿开始使用文本方式初始化PyQuery,使用网上常规html范例文本初始化:

from pyquery import PyQuery as pq

html = '''<div>
<ul id = '5km'>
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
</div>
'''
d = pq(html)

如果想获得classitem-0li,可以:

result = d('#5km .item-0')
print(result)
print(type(result))

运行结果:

<li class="item-0">first item</li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>

<class 'pyquery.pyquery.PyQuery'>

尝试其它的选择器使用,非常方便!

遍历节点

如上面CSS选择器的例子,会选择出三个符合条件的,那我们能不能遍历它们逐一做一些处理呢?当然是没问题了。返回结果会有一个items方法,此方法会得到一个结果对应的生成器,就可以使用for-in进行遍历结果中的每一条li节点了,使用方法如下:

for item in result.items():
    print(item)
    print(type(item))

结果:

<li class="item-0">first item</li>
<class 'pyquery.pyquery.PyQuery'>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<class 'pyquery.pyquery.PyQuery'>
<li class="item-0"><a href="link5.html">fifth item</a></li>
<class 'pyquery.pyquery.PyQuery'>

查询节点

在上面例子中均打印了结果的类型,它们都是PyQuery对象,包含了节点信息。它们具有查询节点的方法,可供获取子孙节点、父节点和兄弟节点。

子孙节点

子孙节点的查询可以使用findchildren两种方法,不同点是,前者可以得到所有子孙节点,而后者只关心子节点信息。为了区分这两种的效果,这里稍微改动一下html内容:

from pyquery import PyQuery as pq

html = '''<div>
<div id="container">
<ul id='5km'>
<li class="item-0">first item</li>
<li class="item-ol">
<ol class='test'>
<li>ol1</li>
<li>ol2</li>
</ol>
</li>
</ul>
</div>
</ddiv>
'''
d = pq(html)
所有子孙节点

使用find方法查询ul 下的 li节点,实现代码如下:

ul = d('#5km')
print(ul.find('li'))

运行结果:

<li class="item-0">first item</li>
<li class="item-ol">
<ol class="test">
<li>ol1</li>
<li>ol2</li>
</ol>
</li>
<li>ol1</li>
<li>ol2</li>

看到结果就明白了,此方法把ul第二个直接子节点下的两个li节点也查询并入查询结果了。下面我们看一下children方法的效果。

直接子节点

利用children方法查询ul下的li节点,当然也可以使用CSS选择器:

print(ul.children('li'))

运行结果:

<li class="item-0">first item</li>
<li class="item-ol">
<ol class="test">
<li>ol1</li>
<li>ol2</li>
</ol>
</li>

不出所料,结果中只有直接子节点,其实children方法可以不加参数,就会返回所有的直接子节点。

祖先节点

按照继承的思路,查询祖先节点就是找父节点、父节点的父节点等等一直按照继承关系向上查询节点。有两个方法:parentparents,前者用来查找直接父节点,后者用来查询所有祖先节点。继续使用前面的d。

直接父节点

直接父节点可以通过parent方法进行查询:

print(ul.parent())

运行结果:

<div id="container">
<ul id="5km">
<li class="item-0">first item</li>
<li class="item-ol">
<ol class="test">
<li>ol1</li>
<li>ol2</li>
</ol>
</li>
</ul>
</div>

此方法直接返回了ul节点的直接父节点<div id='container'的内容。

所有祖先节点

parents方法可以查询所有祖先节点,可以使用CSS选择器,也可以不加参数使用:

print(ul.parents('div'))

查询祖先节点中所有的div节点,返回结果:

<div>
<div id="container">
<ul id="5km">
<li class="item-0">first item</li>
<li class="item-ol">
<ol class="test">
<li>ol1</li>
<li>ol2</li>
</ol>
</li>
</ul>
</div>

</div><div id="container">
<ul id="5km">
<li class="item-0">first item</li>
<li class="item-ol">
<ol class="test">
<li>ol1</li>
<li>ol2</li>
</ol>
</li>
</ul>
</div>

可以看到得到了两层div节点的内容。

兄弟节点

兄弟节点的获取需要使用方法siblings,首先我们获取classitem-olli节点,然后调用siblings方法找到所有兄弟节点:

li = d('#5km .item-ol')
print(li.siblings())

运行结果:

<li class="item-0">first item</li>

classitem-0的节点即为结果。

获取节点信息

节点信息一般就是节点文本和节点的属性了,分别进行探索。

节点文本

节点文本的获取有两种方法:

  • text:获取节点内所有文本及子孙节点的文本内容;
  • html:获取节点的html文本;

这里以classtestol节点为例说明两个方法的使用:

ol = d('#5km .item-ol .test')
print(ol.text())
print(ol.html())

运行结果:

ol1
ol2

<li>ol1</li>
<li>ol2</li>

可以看到按照预期结果分别得到了所有文本信息和html文本。

节点属性

有两种方法可以获取节点属性:

  • 使用节点的attr方法,参数传入待获取属性的名称,比如classidhref等,形如attr('class')
  • 使用节点attr属性的属性,点语法获取,形如attr.href,这里要查询class属性的值比较特殊,因为与python的关键词冲突,所以以此方法查询节点的class属性的话,应该以attr.class_的形式访问查询;
  • 作为字典的形式访问,以属性名作为键值访问,形如attr['class']

举例说明:

print(ol.attr('class'))
print(ol.attr.class_)
print(ol.attr['class'])

运行结果:

test
test
test

上面用三种形式查询了ol节点的class属性。

总结

本文主要一起探索了一下pyquery使用的冰山一角,主要集中的是初始化和读取的操作,其实还有修改节点的功能,因为爬虫程序中大部分还是只用查询解析功能,所以本文只简单列举了节点解析读取功能的具体操作,后面如果有新的总结会持续更新。