学习一时爽,一直学习一直爽css
Hello,你们好,我是 Connor,一个个从无到有的技术小白。上一次咱们说到了 BeautifulSoup
美味的汤,BeautifulSoup
很适合刚刚接触爬虫的新手使用。虽然 BeautifulSoup
好用,可是也有它的局限性。今天咱们来说一讲 PyQuery
,让咱们以 JQuery的方式来快速提取咱们想要的内容。废话很少说,让咱们开始吧。html
pyquery 容许您在 xml 文档上进行 jquery 查询。API 尽量与 jquery 相似。pyquery 使用lxml 进行快速 xml 和 html 操做。固然这并不能用于生成 JavaScript 代码或者与 JavaScript 进行代码交互。因此,若是你想在 Python 上运行 JavaScript 代码,那么 pyquery 不是一个好的选择。python
pyquery仍是很是容易上手的。如今,咱们如下面的这段 xml 代码为例,进行演示:jquery
html = """
<html>
<head>
<title>个人示例</title>
</head>
<body>
<div class="book">
<a class="book_title" id="book" href="abc.html">百炼成钢</a>
<p class="book_author" id="author" >王者之势</p>
<p class="time" id="time">2019/01/13</p>
</div>
</body>
</html>
"""
复制代码
首先,咱们先将这段文档变成 PyQuery
对象,pyquery的操做基本都是经过PyQuery
对象来进行的。你能够这样作:工具
In [2]: from pyquery import PyQuery
In [3]: doc = PyQuery(html)
In [4]: type(doc)
Out[4]: pyquery.pyquery.PyQuery
复制代码
使用 CSS 选择器能够快速地对节点进行选择,CSS 选择器是一种快速高效的选择方式,它能够在页面中实现 一对一,一对多,多对一的多种控制,使用 CSS 选择器无疑是一种快速便捷的提取方式,你只须要像JQuery同样进行选择能够了:post
In [10]: print(doc(".book"))
<div class="book">
<a class="book_title" id="book" href="abc.html">百炼成钢</a>
<p class="book_author" id="author">王者之势</p>
<p class="time" id="time">2019/01/13</p>
</div>
复制代码
能够看到,只要像JQuery同样进行选择就能够垂手可得的将咱们想要的东西就选择出来了,并且不须要像Xpath同样去找它的路径学习
在 pyquery
中,你能够经过节点名来对节点进行简单的选择,当某个节点在文档中只出现一次的时候,这种方式是最简单的,你无需考虑其余因素的影响,就像这样:url
In [11]: c = doc("a")
In [12]: print(c)
<a class="book_title" id="book" href="abc.html">百炼成钢</a>
复制代码
能够看到,很轻松的就将咱们想要的节点选取出来了,可是不少时候某个节点有不少个,不多有单独出现一次的状况,这个时候咱们就须要经过别的方法来进行选择了spa
你也能够经过节点的属性来选择一个节点,当某个节点的某个属性在文档中是惟一的时候,这是最方便的作法。在上面的例子文档中,有不少的节点都拥有惟一的属性,因此,您能够这样作:code
In [13]: c = doc("#author")
In [14]: print(c)
<p class="book_author" id="author">王者之势</p>
复制代码
咱们能够看到,经过单独的属性是很容易选取出咱们想要的的内容的,这只是 id 属性, 咱们也可使用 class 属性来进行快速选择,其写法也和 JQuery 相同,这里再也不演示。 可是当咱们遇到其余的属性的时候该怎么办?咱们能够经过指明属性的名称和值来进行选择, 就像这样:
In [15]: c = doc('[href="abc.html"]')
In [16]: print(c)
<a class="book_title" id="book" href="abc.html">百炼成钢</a>
复制代码
就像这样,咱们只是经过一个href属性就选择出了咱们想要的节点。固然,有些时候某个属性也是众多节点一块儿使用的,这个时候你能够结合咱们讲的第一种方法,经过节点名称来进行选择,将节点与属性进行结合,来进行选择:
In [17]: c = doc('p[id="author"]')
In [18]: print(c)
<p class="book_author" id="author">王者之势</p>
复制代码
经过上面的方法,仍是基本上很容易知足咱们的需求了,可是有些时候,当咱们有更高的需求的时候,咱们须要用到css的伪类选择器,下面,咱们将介绍伪类选择器:
当某些节点拥有多个,或者与其它节点有太多重复属性的时候,咱们就须要用到伪类选择器,伪类选择器出了可使用css自带的伪类选择器以外,pyquery 还提供了相似 JQuery
同样的非标准伪类选择器,这些伪类选择器能够帮助咱们快速的进行选择:
In [19]: c = doc("p:first")
In [20]: print(c)
<p class="book_author" id="author">王者之势</p>
复制代码
伪类选择器支持几乎全部的 CSS
标准伪类以及 JQuery
的非标准伪类:
选择器 | 示例 | 示例说明 |
---|---|---|
:checked | input:checked | 选择全部选中的表单元素 |
:disabled | input:disabled | 选择全部禁用的表单元素 |
:empty | p:empty | 选择全部没有子元素的p元素 |
:enabled | input:enabled | 选择全部启用的表单元素 |
:first-of-type | p:first-of-type | 选择每一个父元素是p元素的第一个p子元素 |
:last-child | p:last-child | 选择全部p元素的最后一个子元素 |
:last-of-type | p:last-of-type | 选择每一个p元素是其母元素的最后一个p元素 |
:not(selector) | :not(p) | 选择全部p之外的元素 |
:nth-child(n) | p:nth-child(2) | 选择全部 p 元素的父元素的第二个子元素 |
:nth-last-child(n) | p:nth-last-child(2) | 选择全部p元素倒数的第二个子元素 |
:nth-last-of-type(n) | p:nth-last-of-type(2) | 选择全部p元素倒数的第二个为p的子元素 |
:nth-of-type(n) | p:nth-of-type(2) | 选择全部p元素第二个为p的子元素 |
:only-of-type | p:only-of-type | 选择全部仅有一个子元素为p的元素 |
:only-child | p:only-child | 选择全部仅有一个子元素的p元素 |
:root | root | 选择文档的根元素 |
:target | #news:target | 选择当前活动#news元素(点击URL包含锚的名字) |
:link | a:link | 选择全部未访问连接 |
:visited | a:visited | 选择全部访问过的连接 |
:active | a:active | 选择正在活动连接 |
:hover | a:hover | 把鼠标放在连接上的状态 |
:focus | input:focus | 选择元素输入后具备焦点 |
:first-child | p:first-child | 选择器匹配属于任意元素的第一个子元素的 元素 |
:lang(language) | p:lang(it) | 为 元素的lang属性选择一个开始值 |
选择器 | 示例 | 示例说明 |
---|---|---|
:first | p:first | 选择第一个 元素 |
:last | p:last | 选择最后一个 元素 |
:odd | p:odd | 选择全部 元素中索引为奇数的元素 |
:even | p:even | 选择全部 元素中索引为偶数的元素 |
:eq(index) | p:eq(0) | 选择全部 元素中索引为0的元素 |
:lt(index) | p:lt(3) | 选择全部 元素中索引小于3的元素 |
:gt(index) | p:gt(2) | 选择全部 元素中索引大于2的元素 |
:header | :header | 选择全部的H1-H6的元素 |
:hidden | p:hidden | 选取全部 元素中包含有隐藏属性的元素 |
:contains(text) | p:contains(王者) | 选择全部 元素中内容包含有‘王者’的元素 |
:has(selector) | div:has(p) | 选择全部带有 元素的
元素
|
:input | :input | 选择全部的<input> 元素 |
:(type)type指input的类型 | :submit | 选择全部type为submit的<input> 元素 |
input的类型包括 |
---|
button submit reset text checkbox image hidden file |
经过上列的伪类你能够更快更方便的对节点进行选择,固然 pyquery
并不仅有这些功能,它还有更多的功能:
当咱们使用 PyQuery
进行选择的时候,不免会遇到某个节点都是使用同一种方式来进行封装的,他们的描述方式都是相同的,亦或者咱们想要批量的选取某个东西的时候,他们的封装形式是相同的,这样很难进行单一的选取。或者说单一选取太麻烦了。此时咱们就须要考虑选择后的遍历问题了。由于一个东西若是不能遍历,对咱们取值有很大的困难,PyQuery
天然也是能够进行遍历的,可能你会这样作:
In [21]: c = doc('p')
In [22]: for item in c:
...: print(item)
...:
<Element p at 0x21395a4b448>
<Element p at 0x21395a12888>
复制代码
你会发现,经过这种方式打印出来的只是一个内存地址,并无实际的东西。当咱们须要遍历 PyQuery
选择出来的东西的时候,咱们须要使用 items()
方法。经过这种方法能够将选择的多个内容区分开来:
In [23]: c = doc('p').items()
In [24]: for item in c:
...: print(item)
...:
<p class="book_author" id="author">王者之势</p>
<p class="time" id="time">2019/01/13</p>
复制代码
经过 items()
方法就能够打印出每一项的内容了。
当咱们获取到指定的节点的时候,有时候咱们须要获取他的文本内容,这个时候就须要的使用 text()
方法了,这个方法能够取出当前 PyQuery
对象中的文本内容,例如:
In [25]: c = doc('#author')
In [26]: print(c.text())
王者之势
复制代码
有些时候咱们不仅是须要提取文本内容,有时候咱们也须要提取节点中的属性内容,例如 href,这个时候咱们就须要使用到 attr()
方法,经过该方法来进行属性内容的提取:
In [13]: tags = doc('a').attr('href')
...: print(tags)
abc.html
复制代码
若是你所选择的当前节点还有子节点,那么你能够经过 html()
方法将当前节点下的全部子元素选择出来,固然,你也能够对它进行更改,改变当前节点下的内容:
In [27]: c = doc('div')
In [28]: print(c.html())
<a class="book_title" id="book" href="abc.html">百炼成钢</a>
<p class="book_author" id="author">王者之势</p>
<p class="time" id="time">2019/01/13</p>
复制代码
或者你能够经过向html()方法中给参数的方法来改变当前节点下的子节点内容:
In [29]: c = doc('div')
In [30]: print(c.html('abcdefghijklmnopqrstuvwxyz'))
<div class="book">abcdefghijklmnopqrstuvwxyz</div>
复制代码
在找到某一节点的内容以后,你还能够经过 find()
方法来在当前基础上进行二次查找甚至是屡次查找,find()
的使用方法和正常的查找方式是相同的:
In [31]: c = doc('div').find('#author')
In [32]: print(c)
<p class="book_author" id="author">王者之势</p>
复制代码
经过 children()
方法能够快速的选取出某个节点下的全部子节点,该方法一样适用于屡次查找,该方法的使用方法和 find()
方法相似:
In [33]: c = doc('div').children('p')
In [34]: print(c)
<p class="book_author" id="author">王者之势</p>
<p class="time" id="time">2019/01/13</p>
复制代码
当 children()
方法不给参数的时候会默认查找出全部的子节点,请按需使用。
有时候咱们寻找某一节点须要用到 class
但每次都单独去取该属性再进行判断有些太麻烦了,PyQuery
为咱们提供了 has_class()
方法,该方法能够快速的对节点是否拥有指定 class
属性进行判断:
In [35]: tags = doc.find('a').has_class('book_title')
...: print(tags)
True
复制代码
有的时候咱们并不能只验证 class
属性,还有其余的属性须要咱们进行验证,或者使用其它属性来进行验证会更加的方便,这个时候咱们就须要使用 is_()
方法。这个方法能够匹配节点中的任意属性:
In [12]: tags = doc('p').eq(0).is_('[id="author"]')
...: print(tags)
True
复制代码
总的来讲,我以为 pyquery
其实并无像想像中的那么好用,使用起来手感和 Xpath
差不了多少,甚至我我的认为 Xpaht
更加好用一些,其实若是你仔细地看 pyquery
的源码你就会发现,其实它也使用了 Xpaht
,比较讽刺吧,可是 pyquery
确实是在 Xpath
的基础上又作出了很大的改进,好比 伪类选择器 这在必定状况下确实是要比 Xpath
要好用的多,因此其实解析并无什么难易,看你是否找对了适合的工具,就比如是否找到了适合脚的鞋子。找对了工具,事半功倍,找错了工具,事倍功半。但愿你可以灵活运用。
Xpath 也讲了,BeautifulSoup也讲了,甚至PyQuery你也讲了,怎么就是不讲 re 正则呢??别着急,重头戏老是在最后出场,下一次咱们就来说述,如何用 re 正则来获取咱们想要的内容。敬请期待下期-- Python爬虫十六式 - 第七式:正则的艺术
好了,这就是今天的内容了,不知道你今天又学会了多少内容。我是 Connor,一个从无到有的技术小白,愿你能在前进的道路上与我一同前行!
学习一时爽,一直学习一直爽!
Python 爬虫十六式 - 第一式:HTTP协议 >>>
Python 爬虫十六式 - 第二式:urllib 与 urllib3 >>>
Python 爬虫十六式 - 第三式:Requests的用法 >>>
Python 爬虫十六式 - 第四式: 使用Xpath提取网页内容 >>>
Python 爬虫十六式 - 第五式:BeautifulSoup,美味的汤 >>>
Python 爬虫十六式 - 第七式:正则的艺术 >>>
Python 爬虫十六式 - 第八式:实例解析-全书网 >>>