关于测试:Python网页解析库用requestshtml爬取网页

52次阅读

共计 2926 个字符,预计需要花费 8 分钟才能阅读完成。

Python 网页解析库:用 requests-html 爬取网页

1. 开始

Python 中能够进行网页解析的库有很多,常见的有 BeautifulSoup 和 lxml 等。在网上玩爬虫的文章通常都是介绍 BeautifulSoup 这个库,我平时也是罕用这个库,最近用 Xpath 用得比拟多,应用 BeautifulSoup 就不大习惯,很久之前就晓得 Reitz 大神出了一个叫 Requests-HTML 的库,始终没有趣味看,这回可算歹着机会用一下了。

应用 pip install requests-html装置,上手和 Reitz 的其余库一样,轻松简略:

from requests_html import HTMLSession
session = HTMLSession()

r = session.get('https://www.python.org/jobs/')

这个库是在 requests 库上实现的,r 失去的后果是 Response 对象上面的一个子类,多个一个 html 的属性。所以 requests 库的响应对象能够进行什么操作,这个 r 也都能够。如果须要解析网页,间接获取响应对象的 html 属性:

r.html

2. 原理

不得不膜拜 Reitz 大神太会组装技术了。实际上 HTMLSession 是继承自 requests.Session 这个外围类,而后将 requests.Session 类里的 requests 办法改写,返回本人的一个 HTMLResponse 对象,这个类又是继承自 requests.Response, 只是多加了一个 _from_response 的办法来结构实例:

class HTMLSession(requests.Session):
    # 重写 request 办法,返回 HTMLResponse 结构
    def request(self, *args, **kwargs) -> HTMLResponse:
        r = super(HTMLSession, self).request(*args, **kwargs)
        return HTMLResponse._from_response(r, self)
class HTMLResponse(requests.Response):
    # 结构器
    @classmethod
    def _from_response(cls, response, session: Union['HTMLSession', 'AsyncHTMLSession']):
        html_r = cls(session=session)
        html_r.__dict__.update(response.__dict__)
        return html_r

之后在 HTMLResponse 里定义属性办法 html,就能够通过 html 属性拜访了, 实现也就是组装 PyQuery 来干。外围的解析类也大多是应用 PyQuery 和 lxml 来做解析,简化了名称,挺讨巧的。

3. 元素定位

元素定位能够抉择两种形式:

css 选择器
  • css 选择器
  • xpath
# css 获取有多少个职位
jobs = r.html.find("h1.call-to-action")
# xpath 获取
jobs = r.html.xpath("//h1[@class='call-to-action']")

办法名非常简单,合乎 Python 优雅的格调,这里无妨对这两种形式简略的阐明:

4. CSS 简略规定

  • 标签名 h1
  • id 应用 #id 示意
  • class 应用 .class_name 示意
  • 谓语示意:h1[prop=value]

5. Xpath 简略规定

  • 门路 // 或者 /
  • 标签名
  • 谓语 [@prop=value]
  • 轴定位 名称:: 元素名[谓语]

定位到元素当前势必要获取元素外面的内容和属性相干数据,获取文本:

jobs.text
jobs.full_text

获取元素的属性:

attrs = jobs.attrs
value = attrs.get("key")

还能够通过模式来匹配对应的内容:

## 找某些内容匹配
r.html.search("Python {}")
r.html.search_all()

这个性能看起来比拟鸡肋,能够深入研究优化一下,说不定能在 github 上混个提交。

6. 人性化操作

除了一些根底操作,这个库还提供了一些人性化的操作。比方一键获取网页的所有超链接,这对于整站爬虫应该是个福音,URL 治理比拟不便:

r.html.absolute_links
r.html.links

内容页面通常都是分页的,一次抓取不了太多,这个库能够获取分页信息:

print(r.html)
# 比拟一下
for url in r.html:
    print(url)

后果如下:

# print(r.html)
<HTML url='https://www.python.org/jobs/'>
# for
<HTML url='https://www.python.org/jobs/'>
<HTML url='https://www.python.org/jobs/?page=2'>
<HTML url='https://www.python.org/jobs/?page=3'>
<HTML url='https://www.python.org/jobs/?page=4'>
<HTML url='https://www.python.org/jobs/?page=5'>

通过迭代器实现了智能发现分页,这个迭代器外面会用一个叫 _next 的办法,贴一段源码感触下:

def get_next():
    candidates = self.find('a', containing=next_symbol)

    for candidate in candidates:
        if candidate.attrs.get('href'):
            # Support 'next' rel (e.g. reddit).
            if 'next' in candidate.attrs.get('rel', []):
                return candidate.attrs['href']

通过查找 a 标签外面是否含有指定的文原本判断是不是有下一页,通常咱们的下一页都会通过 下一页 或者 加载更多 来疏导,他就是利用这个标记来进行判断。默认的以列表模式存在全局:['next', 'more', 'older']。我集体认为这种形式十分不灵便,简直没有扩展性。 感兴趣的能够往 github 上提交代码优化。

7. 加载 js

兴许是思考到了当初 js 的一些异步加载,这个库反对 js 运行时,官网阐明如下:

Reloads the response in Chromium, and replaces HTML content
with an updated version, with JavaScript executed.

应用非常简单,间接调用以下办法:

r.html.render()

第一次应用的时候会下载 Chromium,不过国内你懂的,本人想方法去下吧,就不要等它本人下载了。render 函数能够应用 js 脚本来操作页面,滚动操作独自做了参数。这对于上拉加载等旧式页面是十分敌对的。

8. 总结

Reitz 大神设计进去的货色还是判若两人的简略好用,本人不多做,大多用他人的货色组装,简化 api。真是够兽性。不过有的中央还是优化空间,心愿有趣味和精力的童鞋去 github 上关注一下这个我的项目。

正文完
 0