requests-html是requests的升级版,出自同一个作者之手。
requests-html是对requests,lxml,pyppeteer等的封装,git地址
中文文档手册,刚发现的
安装 pip install requests-html
可能会报错,重复装几次
全面支持解析JavaScript
CSS 选择器.
XPath 选择器
自定义user-agent
自动追踪重定向.
连接池与cookie持久化.
首先要求的版本必须是python3.6版本以上才能使用【assert(python断言)】
1、简单使用 HTMLSession
from requests_html import HTMLSession #一般请求使用HTMLSession
session = HTMLSession()
# 对京东数据进行拿取
r = session.get('https://search.jd.com/Search?keyword=x1&enc=utf-8&wq=x1&pvid=add52cb63f7e4887b5ba29406a5756ba')
#直接通过css进行标签定位
link_list = r.html.find('.gl-item')
for i in link_list:
print(i.text)
如上,简单的几行代码就可以操作出如下的结果
2、javascript加载 render
render加载的过程中,需要下载chromium,这是利用pyppeteer使用chromium进行加载,对网页上后边需要渲染的异步js进行加载。由于不是国内镜像,下载看个人网络环境。在公司直接下载成功的,这里不行了,就先不更新了
更新 (公司环境)
这是对文章的拿取(我的个人主页)
的文章是明显的ajax加载的异步请求,鼠标滑动进行多次请求
这里的代理是进行一次普通的请求,
from requests_html import HTMLSession
session = HTMLSession()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'
}
res = session.get('https://www.jianshu.com/u/01b1488fd0b8', headers=headers)
titles = res.html.find('a.title')
for i, title in enumerate(titles):
print(f'{i + 1} [{title.text}](https://www.jianshu.com{title.attrs["href"]})')
通过render进行多次下滑加载
from requests_html import HTMLSession
session = HTMLSession()
r = session.get('https://www.jianshu.com/u/01b1488fd0b8')
r.html.render(scrolldown=70, sleep=.2) # scrolldown向下滑动的参数
titles = r.html.find('a.title')
for i, title in enumerate(titles):
print(f'{i + 1} [{title.text}](https://www.jianshu.com{title.attrs["href"]})')
由上可见,reqeusts_html对异步加载也具有良好的支持
它就是一个微型的框架,直接携程并发操作,但是由于试用Chrome内核进行加载js,所以说响应比较慢点,但是对于一些复杂的js来说据十分好用了。
2.1 render内部方法(使用持续更新)
retries: 加载页面失败的次数
script: 页面上需要执行的JS脚本(可选)
wait: 加载页面钱的等待时间(秒),防止超时(可选)
scrolldown: 页面向下滚动的次数
sleep: 在页面初次渲染之后的等待时间
reload: 如果为假,那么页面不会从浏览器中加载,而是从内存中加载
keep_page: 如果为真,允许你用r.html.page访问页面
3、源码解析(部分,主要是实力不允许啊,随着技术见长会更新认知)
下边是导入的包,通过导入的包进行了解用到的模块
from fake_useragent import UserAgent
不用手动封装请求头了
import sys
import asyncio
from urllib.parse import urlparse, urlunparse, urljoin
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures._base import TimeoutError
from functools import partial
from typing import Set, Union, List, MutableMapping, Optional
import pyppeteer #这是进行javascript加载的核心,无头浏览器
import requests
from pyquery import PyQuery
from fake_useragent import UserAgent
from lxml.html.clean import Cleaner
import lxml
from lxml import etree
from lxml.html import HtmlElement
from lxml.html import tostring as lxml_html_tostring
from lxml.html.soupparser import fromstring as soup_parse
from parse import search as parse_search
from parse import findall, Result
from w3lib.encoding import html_to_unicode
BaseSession是整个框架的核心,继承了requests.Session保证cookie一直在链接的过程中
class BaseSession(requests.Session):
""" A consumable session, for cookie persistence and connection pooling,
amongst other things.(一个可消费会话,用于cookie持久性和连接池,
在其他的事情)
"""
def __init__(self, mock_browser : bool = True, verify : bool = True,
browser_args : list = ['--no-sandbox']):
super().__init__()
# Mock a web browser's user agent.
if mock_browser:
self.headers['User-Agent'] = user_agent()
self.hooks['response'].append(self.response_hook)
self.verify = verify
self.__browser_args = browser_args
def response_hook(self, response, **kwargs) -> HTMLResponse:
""" Change response enconding and replace it by a HTMLResponse. """
if not response.encoding:
response.encoding = DEFAULT_ENCODING
return HTMLResponse._from_response(response, self)
@property
async def browser(self):
if not hasattr(self, "_browser"):
self._browser = await pyppeteer.launch(ignoreHTTPSErrors=not(self.verify), headless=True, args=self.__browser_args)
return self._browser
HTMLSession 继承了BaseSession,进行并发操作
class HTMLSession(BaseSession):
def __init__(self, **kwargs):
super(HTMLSession, self).__init__(**kwargs)
@property
def browser(self):
if not hasattr(self, "_browser"):
self.loop = asyncio.get_event_loop()
if self.loop.is_running():
raise RuntimeError("Cannot use HTMLSession within an existing event loop. Use AsyncHTMLSession instead.")
self._browser = self.loop.run_until_complete(super().browser)
return self._browser
def close(self):
""" If a browser was created close it first. """
if hasattr(self, "_browser"):
self.loop.run_until_complete(self._browser.close())
super().close()