用pyquery5行代码爬取百度热点新闻

 

导读:学习python爬虫很久了,一直习惯于requests抓取+xpath解析的两步走套路,直到我今天发现了pyquery这个爬虫利器后,才意识到python的世界没有最简,只有更简……

2020-03-06 21:22:12


 

01 pyquery简介

pyquery是Python的一个第三方爬虫库,仿照 jQuery实现,语法与js十分相像。如果有js基础,那么应用pyquery简直是平步青云。pyquery自带网页解析和信息提取功能,所以应用起来会非常简洁。

pyquery安装(要求cssselect和lxml库支持):

pip install pyquery

安装好pyquery包后,默认可在..\Python\Python37\Lib\site-packages目录下找到pyquery文件,主要包括5个.py文件,分别是pyquery.py、 opener.py、 cssselectpath.py、 text.py以及一个初始化文件__init__.py,其中pyquery是主应用模块,内部调用其他3个模块。在pyquery模块中,实现了多个类,其中PyQuery是主类,继承列表类(所以列表的所有接口PyQuery都可以调用)。如下命令获取其所有方法接口:

from pyquery import PyQuery as pq
dir(pq)

 

02 pq初始化

pyquery的初始化可接收4种格式的参数,分别是字符串类型、html、html文件地址以及需要请求的ur相关信息,尤其是支持请求url的初始化方式,大大简化了的爬虫代码实现。

  • 接收字符串
doc = pq("<html>hello, world</html>")
  • 接收html

doc = pq(etree.fromstring("<html>hello, world</html>")
  • 接收html文件地址

doc = pq(filename=path_to_html_file)
  • 接受URL及相关信息

这里具体讲解pyquery接收url相关信息的实现方式。查看pyquery初始化方法,其接收不定参数和字典参数如下:

def __init__(self, *args, **kwargs):
        html = None
        elements = []
        self._base_url = None
        self.parser = kwargs.pop('parser', None)

        if (len(args) >= 1 and
                isinstance(args[0], string_types) and
                args[0].split('://', 1)[0] in ('http', 'https')):
            kwargs['url'] = args[0]
            if len(args) >= 2:
                kwargs['data'] = args[1]
            args = []
        pass

 

当接受参数满足:①参数个数大于等于1个、②第一个参数为字符串类型、③第一个参数可以解析为http或https格式,则提取url及其相关信息(如headers等)并赋值给字典参数kwargs,进行网页解析:

if kwargs:
    # specific case to get the dom
    if 'filename' in kwargs:
        html = open(kwargs['filename'])
    elif 'url' in kwargs:
        url = kwargs.pop('url')
        if 'opener' in kwargs:
            opener = kwargs.pop('opener')
            html = opener(url, **kwargs)
        else:
            html = url_opener(url, kwargs)
        if not self.parser:
            self.parser = 'html'
        self._base_url = url
    else:
        raise ValueError('Invalid keyword arguments %s' % kwargs)

 

当前一步提取的字典参数不为空,且包含"url"键值时则解析为需要进行网页请求。网页请求中当初始化参数中指定了解析器opener时,则调用指定解析器,否则使用pyquery自定义的url_opener方法进行解析。 进一步查看pyquery自定义的url_opener方法:

try:
    import requests
    HAS_REQUEST = True
except ImportError:
    HAS_REQUEST = False
--------------
def url_opener(url, kwargs):
    if HAS_REQUEST:
        return _requests(url, kwargs)
    return _urllib(url, kwargs)
--------------
def _requests(url, kwargs):
    encoding = kwargs.get('encoding')
    method = kwargs.get('method', 'get').lower()
    session = kwargs.get('session')
    if session:
        meth = getattr(session, str(method))
    else:
        meth = getattr(requests, str(method))
    pass
--------------
def _urllib(url, kwargs):
    method = kwargs.get('method')
    url, data = _query(url, method, kwargs)
    return urlopen(url, data, timeout=kwargs.get('timeout', DEFAULT_TIMEOUT))

至此,我们知道pyquery的自定义解析器采用如下规则:

    • 如果系统当前安装了requests库(第三方库,使用前需手动安装),则调用_requests方法,其中还根据初始化参数中是否指定了session来进一步区分

    • 否则,则调用urllib库(python自带的网页解析库)urlopen方法进行解析

 

可见,pyquery相当于会自动调用requests库或默认的urllib库进行网页解析,且以前者优先,并支持携带requests的session进行解析。

 

03 选择器

pyquery支持与CSS一致的选择器实现方法:

from pyquery import PyQuery as pq
html = '''
    <div id="test">
        <ul class="c1">
            hello
            <link href="http://123.com">this</link>
            <link href="http://456.com">is</link>
            <link href="http://789.com">pyquery</link>
        </ul>
        <ul class="c2">
            world
            <link href="http://321.com">test</link>
            <link href="http://654.com">for</link>
            <link href="http://987.com">spider</link>
        </ul>
    </div>
'''
doc = pq(html)
print(type(doc))#<class 'pyquery.pyquery.PyQuery'>
print(doc("div#test>ul.c1 link"))
"""
<link href="http://123.com">this</link>
            <link href="http://456.com">is</link>
            <link href="http://789.com">pyquery</link>
"""

其中:

  • pyquery初始化后为PyQuery对象类型

  • pyquery使用字符串识别标签和CSS标识

  • 父标签和子标签间可以用>,也可以用空格

  • 可以通过属性选择特定标签,其中id用"#",class用"."

 

04 查找节点

pyquery可以很容易实现查找父类、子类、兄弟节点,主要方法如下:

  • find()选择所有满足条件的子节点
item=doc(".c1")
link = item.find('link')
print(link)
"""
<link href="http://123.com">this</link>
            <link href="http://456.com">is</link>
            <link href="http://789.com">pyquery</link>
            """
  • parents()选择父节点
item=doc(".c1")
p = item.parents()
print(p)
"""
<div id="test">
        <ul class="c1">
            hello
            <link href="http://123.com">this</link>
            <link href="http://456.com">is</link>
            <link href="http://789.com">pyquery</link>
        </ul>
        <ul class="c2">
            world
            <link href="http://321.com">test</link>
            <link href="http://654.com">for</link>
            <link href="http://987.com">spider</link>
        </ul>
    </div>
"""
  • children()选择子节点
item=doc(".c1")
c = item.children()
print(c)
"""
<link href="http://123.com">this</link>
            <link href="http://456.com">is</link>
            <link href="http://789.com">pyquery</link>
"""
  • siblings()选择兄弟节点
item=doc(".c1")
s = item.siblings()
print(s)
"""
<ul class="c2">
            world
            <link href="http://321.com">test</link>
            <link href="http://654.com">for</link>
            <link href="http://987.com">spider</link>
        </ul>
"""

 

05 获取信息

在完成选择节点的基础上,pyquery获取信息实现就非常简单。常用的方法如下:

  • items()获取所有匹配结果(返回一个生成器)
items=doc(".c1 link").items()
print(items)#<generator object PyQuery.items at 0x000001F124C23390>
  • attr()获取属性信息
for item in items:
    print(item.attr('href'))
"""
http://123.com
http://456.com
http://789.com
"""
  • text()获取文本信息
for item in items:
    print(item.text())
"""
this
is
pyquery
"""
  • html()获取相应html文本
h = doc('ul').html()
print(h)
"""
hello
            <link href="http://123.com">this</link>
            <link href="http://456.com">is</link>
            <link href="http://789.com">pyquery</link>
"""

 

06 pyquery实战

了解了基本操作,我们就可以应用pyquery进行快速的网页爬取了。以百度热点新闻为例,进行简单的接口分析获得url后只需要5行代码就可以轻松获取40条搜索热点标题,简直不能比这更方便了!

from pyquery import PyQuery  as pq
doc = pq(url='http://top.baidu.com/buzz?b=1&fr=20811', encoding = 'gb18030')
items = doc("td.keyword>a.list-title").items()
hots = [item.text() for item in items]
print(hots)
# ['春雨医生获投资', '肖战ins头像', '洛杉矶马拉松', '韦特斯加盟湖人', '甘薇弃优先分配权', '硕士研究生扩招', '毛剑卿退役', '皮亚琴察市长确诊', '67台ECMO发往湖北', '伊朗国家动员计划', '雷神山机器人上岗', '上海马拉松升级', '湖北人民免费看剧', '草地贪夜蛾入侵', '快女喻佳丽结婚', '惠普拒绝施乐收购', '汪曾祺百年诞辰', '美国对塔利班空袭', '鼓浪屿将恢复开放', 'Faker2000杀', '小罗因假护照被捕', '杨蓉经纪公司声明', '库里复出23分', '英国确诊人数翻倍', '英国再现集装箱藏人案', 'Facebook员工确诊', '普利兹克建筑奖', '卢浮宫重新开放', '史酷比狗预告', '黄子佼孟耿如结婚', '法国政府征用口罩', '76人vs湖人', '龙卷风袭击美国', '邓肯执教首胜', '英国首例死亡病例', '布隆伯格退出大选', '库里复出', '罗永浩宣布开直播', '湖人战胜76人', '热刺大将怒揍球迷']

 

 

当然,为了实现反爬能力更强和更加高效的爬虫,可以在pyquery初始化时传入更多参数,例如headers、session和timeout等。

  

07 总结

  • pyquery是一个高度集成的python第三方爬虫库,方法众多、实现简洁

  • pyquery内置了网页解析,会首先尝试调用requests库,若当前未安装则调用python内置urllib库解析

  • pyquery解析提取采用类似CSS选择器的方式进行

  • pyquery支持简洁的节点选择、属性和文本提取操作

  • pyquery还有很多其他方法,包括节点操作、伪类选择器等,但爬虫一般不需要用到

 

posted on 2020-03-06 21:16  小数志  阅读(416)  评论(0编辑  收藏  举报

导航