Python使用requests-html库进行网页爬取的完整指南
本文详细介绍Python中requests-html库的安装与核心用法。该库基于requests封装,支持CSS选择器与XPath定位,并能通过Chromium引擎执行JavaScript实现动态页面爬取。文章涵盖元素提取、分页处理及源码解析,帮助开发者快速掌握现代网页数据抓取技巧。
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库构建,获取的 html 对象是Response类的子类,额外增加了对网页解析的支持。因此,requests库响应对象支持的操作,该对象同样适用。若需解析网页,可直接调用响应对象的html属性:
r.html
2. 原理
不得不佩服Reitz大神对技术的巧妙整合。实际上,HTMLSession类继承自requests.Session核心类,并重写了其中的request方法,使其返回自定义的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
考虑到现代网页中JavaScript异步加载的普遍性,该库支持JavaScript运行时,官方说明如下:
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上的该项目。
到此这篇关于Python用requests-html爬取网页的实现的文章就介绍到这了,更多相关Python requests-html爬取内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









