zoukankan      html  css  js  c++  java
  • Python 爬虫十六式

    PyQuery:一个类似jquery的python库

    学习一时爽,一直学习一直爽

      Hello,大家好,我是 Connor,一个从无到有的技术小白。上一次我们说到了 BeautifulSoup 美味的汤,BeautifulSoup 很适合刚刚接触爬虫的新手使用。虽然 BeautifulSoup 好用,但是也有它的局限性。今天我们来讲一讲 PyQuery,让我们以 JQuery的方式来快速提取我们想要的内容。废话不多说,让我们开始吧。

    1. PyQuery 的简介

      pyquery 允许您在 xml 文档上进行 jquery 查询。API 尽可能与 jquery 类似。pyquery 使用lxml 进行快速 xml 和 html 操作。当然这并不能用于生成 JavaScript 代码或者与 JavaScript 进行代码交互。所以,如果你想在 Python 上运行 JavaScript 代码,那么 pyquery 不是一个好的选择。


    2. PyQuery 的简单使用

      pyquery还是非常容易上手的。现在,我们以下面的这段 xml 代码为例,进行演示:

    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一样进行选择可以了:

    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一样去找它的路径


    3. 使用 PyQuery 选择单一节点

    3.1 通过节点名称进行选择

      在 pyquery 中,你可以通过节点名来对节点进行简单的选择,当某个节点在文档中只出现一次的时候,这种方式是最简单的,你无需考虑其他因素的影响,就像这样:

    In [11]: c = doc("a")
    
    In [12]: print(c)
    <a class="book_title" id="book" href="abc.html">百炼成钢</a>
    

      可以看到,很轻松的就将我们想要的节点选取出来了,但是很多时候某个节点有很多个,很少有单独出现一次的情况,这个时候我们就需要通过别的方法来进行选择了


    3.2 通过属性进行选择

      你也可以通过节点的属性来选择一个节点,当某个节点的某个属性在文档中是唯一的时候,这是最方便的做法。在上面的例子文档中,有很多的节点都拥有唯一的属性,所以,您可以这样做:

    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的伪类选择器,下面,我们将介绍伪类选择器:


    3.3 通过伪类来进行选择

      当某些节点拥有多个,或者与其它节点有太多重复属性的时候,我们就需要用到伪类选择器,伪类选择器出了可以使用css自带的伪类选择器之外,pyquery 还提供了类似 JQuery 一样的非标准伪类选择器,这些伪类选择器可以帮助我们快速的进行选择:

    In [19]: c = doc("p:first")
    
    In [20]: print(c)
    <p class="book_author" id="author">王者之势</p>
    

      伪类选择器支持几乎所有的 CSS 标准伪类以及 JQuery 的非标准伪类:

    CSS 标准伪类

    选择器 示例 示例说明
    :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以外的元素
    :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属性选择一个开始值

    上表部分取自--菜鸟教程

    JQuery 非标准伪类

    选择器 示例 示例说明
    :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§ 选择所有带有

    元素的

    元素

    :input :input 选择所有的元素
    :(type)type指input的类型 :submit 选择所有type为submit的元素
    input的类型包括
    button submit reset text checkbox image hidden file

      通过上列的伪类你可以更快更方便的对节点进行选择,当然 pyquery 并不只有这些功能,它还有更多的功能:


    4. 使用 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() 方法就可以打印出每一项的内容了。


    5. PyQuery 的其它使用方法

    5.1 text() 方法

      当我们获取到指定的节点的时候,有时候我们需要获取他的文本内容,这个时候就需要的使用 text() 方法了,这个方法可以取出当前 PyQuery 对象中的文本内容,例如:

    In [25]: c = doc('#author')
    
    In [26]: print(c.text())
    王者之势
    

    5.2 attr() 方法

      有些时候我们不只是需要提取文本内容,有时候我们也需要提取节点中的属性内容,例如 href,这个时候我们就需要使用到 attr() 方法,通过该方法来进行属性内容的提取:

    In [13]: tags = doc('a').attr('href')
        ...: print(tags)
    abc.html
    

    5.3 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>
    

    5.4 find() 方法

      在找到某一节点的内容之后,你还可以通过 find() 方法来在当前基础上进行二次查找甚至是多次查找,find() 的使用方法和正常的查找方式是相同的:

    In [31]: c = doc('div').find('#author')
    
    In [32]: print(c)
    <p class="book_author" id="author">王者之势</p>
    

    5.5 children() 方法

      通过 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() 方法不给参数的时候会默认查找出所有的子节点,请按需使用。


    5.6 has_class() 方法

      有时候我们寻找某一节点需要用到 class 但每次都单独去取该属性再进行判断有些太麻烦了,PyQuery 为我们提供了 has_class() 方法,该方法可以快速的对节点是否拥有指定 class 属性进行判断:

    In [35]: tags = doc.find('a').has_class('book_title')
        ...: print(tags)
    True
    

    5.7 is_() 方法

      有的时候我们并不能只验证 class 属性,还有其他的属性需要我们进行验证,或者使用其它属性来进行验证会更加的方便,这个时候我们就需要使用 is_() 方法。这个方法可以匹配节点中的任意属性:

    In [12]: tags = doc('p').eq(0).is_('[id="author"]')
        ...: print(tags)
    True
    

    5.9 对上述方法的总结

      总的来说,我觉得 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 爬虫十六式 - 第七式:正则的艺术 >>>

  • 相关阅读:
    ZOJ 2158 Truck History
    Knight Moves (zoj 1091 poj2243)BFS
    poj 1270 Following Orders
    poj 2935 Basic Wall Maze (BFS)
    Holedox Moving (zoj 1361 poj 1324)bfs
    ZOJ 1083 Frame Stacking
    zoj 2193 Window Pains
    hdu1412{A} + {B}
    hdu2031进制转换
    openjudge最长单词
  • 原文地址:https://www.cnblogs.com/miss85246/p/10397601.html
Copyright © 2011-2022 走看看