龙空技术网

「Python自学笔记」新手必备!Python爬虫requests_html模块

XiaoqiangClub 267

前言:

此时大家对“html获取object”大约比较讲究,同学们都需要分析一些“html获取object”的相关资讯。那么小编也在网络上搜集了一些有关“html获取object””的相关资讯,希望各位老铁们能喜欢,看官们快快来学习一下吧!

安装基本使用发送请求解析响应获获取需要的内容快速获取链接获取元素高级功能JS渲染自动翻页(不太好用)异步异步渲染JS异步发送请求初识requests_html模块

感觉只要学过Python爬虫的同学应该都知道requests这个库吧,它在我们的Python爬虫任务中应该是最常用的一个库了!今天跟大家分享的这个模块requests_html,他的作者和前者是同一人!这是一个解析HTML的库,用起来和requests一样方便,下面就来介绍一下它!

参考视频使用requests_html安装依然是那个命令 pip3 install -i requests_html注意:由于requests_html模块中使用了异步asynico模块,所以官方声明,需要在python3.6以上版本才能正常使用!基本使用发送请求requests_html发送请求获取页面需要先实例化一个HTMLSession对象,然后使用get/post...方法获取响应,如下列代码

#!/usr/bin/env python3# coding     : utf-8# Author     : xiao qiang# 微信公众号   : xiaoqiangclub# Software   : PyCharm# File       : test.py# Time       : 2021/5/29 7:57from requests_html import HTMLSessionif __name__ == '__main__':    url = ';    session = HTMLSession()  # 获取实例化session对象    r = session.get(url)    # 这里的请求和requests的几乎一样!同样可以根据需要添加headers等参数
requests_html发送请求的方式和requests中使用session方式发送请求几乎是一样的,可以对比参考requests_html同样可以发送get/post等请求,且可以和requests同样携带headers/data等参数,具体用法参考requests解析响应获接上,我们需要将获取的响应解析获取html页面,在这里我们同样可以使用requests中的r.content.decode()等原方法!但是在requests_html中还提供了更便捷的方法:r.html.htmlr.html.html实际上是使用了requests_html中的HTML类(负责对HTML进行解析)来进行解析!如下
#!/usr/bin/env python3# coding     : utf-8# Author     : xiao qiang# 微信公众号   : xiaoqiangclub# Software   : PyCharm# File       : test.py# Time       : 2021/5/29 7:57from requests_html import HTMLSessionif __name__ == '__main__':    url = ';    session = HTMLSession()  # 获取实例化session对象    r = session.get(url)  # 这里的请求和requests的几乎一样!同样可以根据需要添加headers等参数    # 获取html页面    # html = r.content.decode()  # requests方式    get_html = r.html.html  # requests_html中的方法    print(get_html[:15], '...')
运行结果(这里只显示了部分结果!)获取需要的内容快速获取链接requests_html中提供了快速获取网址链接的方法使用linksabsolute_links两个属性分别可以返回HTML对象所包含的所有链接和绝对链接(均不包含锚点)
# 快速获取链接pprint(r.html.links)  # 获取html中的链接(href属性)pprint(r.html.absolute_links)  # 会自动拼接url生成绝对链接
部分运行结果如下获取元素requests_html中的HTML对象可以直接使用xpathcss选择器使用xpathrequests_html中的HTML对象支持xpath语法,它有以下几个参数:
def xpath(self, selector: str, *, clean: bool = False, first: bool = False, _encoding: str = None) -> _XPath:- selector,要用的 xpath选择器;- clean,布尔值,如果为True,会清除HTML中style和script标签;- first,布尔值,如果为True,会返回第一个元素,否则会返回满足条件的元素列表;- _encoding,编码格式。
接上面的例子!使用获取到的响应得到HTML对象r.html
pprint(r.html.xpath('//li[@class="hotsearch-item odd"]/a'))pprint(r.html.xpath('//li[@class="hotsearch-item odd"]/a', first=True).text)
运行结果xpath语法使用css选择器(find方法)requests_html中的HTML对象支持css选择器,它有以下几个参数:
def find(self, selector: str = "*", *, containing: _Containing = None, clean: bool = False, first: bool = False, _encoding: str = None) -> _Find:- selector,要用的CSS选择器;- clean,布尔值,如果为True,会清除HTML中style和script标签;- containing,如果设置该属性,只返回包含该属性文本的标签;- first,布尔值,如果为True,会返回第一个元素,否则会返回满足条件的元素列表;- _encoding,编码格式。
接上面的例子!使用获取到的响应得到HTML对象r.html
pprint(r.html.find('a.mnav'))pprint(r.html.find('a.mnav', first=True).text)
运行结果css选择器语法可以使用text属性来获取元素的文本内容

pprint(r.html.find('a.mnav')[0].text)

执行结果如果要获取元素的attribute,用attrs属性

pprint(r.html.find('a.mnav')[0].attrs)

执行结果获取到attrs属性后,就可以使用字典的相关方法获取内容了!最后还可以使用html属性获取一个元素的html代码,如下

pprint(r.html.find('a.mnav')[0].html)

执行结果正则搜索(search、search_all)requests_html除了上面的方式还可以使用search/search_all来直接搜索内容,返回的是一个Result对象/Result对象列表实际上是作者将re正则进行了封装)!

def search(self, template: str) -> Result:# 只有一个参数template: 就是要检索的内容,这里使用英文状态的 {} 来获取内容,有点类似正则里面的 ()
使用英文状态的 {} 来获取内容,如下
    ret = r.html.find('a.mnav')[0].search('新{}')    pprint(ret)    pprint(type(ret))    pprint(ret[0])
执行结果search()获取到的是第一个匹配的对象,而searchh_all()则是获取所有匹配的对象,得到的是一个列表,如下

ret = r.html.find('a.mnav')[0].search_all('新{}')

pprint(ret)

pprint(type(ret))

pprint(ret[0][0])

运行结果除了对某个元素进行检索外,还可以直接对html对象进行搜索,如下

ret = r.html.search_all('百度{}')

pprint(ret)

pprint(type(ret))

pprint(ret[0][0])

运行结果requests_html内容提取的方式这么多,大家可以根据需要和习惯选择使用!

search补充

在上面提到的search()/search_all()方法中,我们设定的template参数可以有多个取值(多个{}),得到的结果是一个列表,我们可以遍历别表进行取值 取值的时候可以通过result[索引]的方式进行获取对应的数据,如下(示例部分代码) search_ret = r.html.search_all('<a h{}f="{}"',)

print(search_ret)

for ret in search_ret:

print(ret)

print(ret[1])

print('--------------')

运行结果(部分)除此之外,我们还可以对取值进行命名,返回的结果是可以使用类似字典(不是字典)[name]的方式取值(不能使用get),如下示例(部分代码) search_ret = r.html.search_all('<a h{test}f="{url}"',)

print(search_ret)

for ret in search_ret:

print(ret)

print(ret['name'])

print('--------------')运行结果(部分)以上就是对requests_html模块search()/search_all()方法的补充内容!HTML类requests_html中使用HTML类负责对HTML进行解析HTML类不仅可以解析网络请求获取的响应,还可以直接解析html文本,如下

>>> from requests_html import HTML>>> doc = """<a href=';>""">>> html = HTML(html=doc)>>> html.links{';}
还可以直接渲染JS,如下
# 和上面一段代码接起来>>> script = """        () => {            return {                width: document.documentElement.clientWidth,                height: document.documentElement.clientHeight,                deviceScaleFactor: window.devicePixelRatio,            }        }    """>>> val = html.render(script=script, reload=False) # render()方法 后面会讲>>> print(val){'width': 800, 'height': 600, 'deviceScaleFactor': 1}>>> print(html.html)<html><head></head><body><a href=";></a></body></html>
高级功能前面介绍的是requests_htmlrequests库的基础上整合的html解析&数据筛选的功能!下面要为大家介绍的是requests_html模块中的一些高级功能:自动渲染JS&智能分页JS渲染我们在做爬虫项目的时候会遇到网站的页面是由js生成的情况!这个时候要么就是自己去一步一步地分析请求,要么就是使用selenium等第三方库来进行渲染页面,为了解决这个难题,requests_html模块中引进了pyppeteer,使用pyppeteer可以像使用selenium一样实现网站的完整加载!而且pyppeteer是一个异步模块!效率会更高!requests_html模块在HTML对象的基础上使用render()方法重新加载js页面注意:在第一次使用render()的时候,系统在用户目录(默认是~/.pyppeteer/)中下载一个chromium。下载过程只在第一次执行,以后就可以直接使用chromium来执行任务了。在没有科学上网的环境下可能下载速度有点慢,请耐心等待...下面是一个官方示例
>>> r = session.get(';)>>> r.html.render()[W:pyppeteer.chromium_downloader] start chromium download.Download may take a few minutes.[W:pyppeteer.chromium_downloader] chromium download done.[W:pyppeteer.chromium_downloader] chromium extracted to: C:\Users\xxxx\.pyppeteer\local-chromium\571375>>> r.html.search('Python 2 will retire in only {months} months!')['months']'<time>25</time>'
requests_html模块在HTML对象的基础上使用render()方法重新加载js页面,它有以下几个参数:
def render(self, retries: int = 8, script: str = None, wait: float = 0.2, scrolldown=False, sleep: int = 0, reload: bool = True, timeout: Union[float, int] = 8.0, keep_page: bool = False):- retries: 加载页面失败的次数- script: 页面上需要执行的JS脚本(可选)- wait: 加载页面前等待的时间(秒),防止超时(可选)- scrolldown: 页面向下滚动的次数(整数)- sleep: 在页面初次渲染之后的等待时间- reload: 如果为False,那么页面不会从浏览器中加载,而是从内存中加载,只有设置为True才会在浏览器中渲染JS- keep_page: 如果为True,允许您使用 r.html.page 访问浏览器页面
requests_html还支持异步渲染JS[^1]自动翻页(不太好用)很多网站会出现翻页的情况,requests_html模块的HTML对象中提供了一个next()方法来实现自动翻页!requests_html模块在HTML对象的基础上使用next()方法来实现自动翻页!它有以下几个参数:
def next(self, fetch: bool = False, next_symbol: _NextSymbol = DEFAULT_NEXT_SYMBOL) -> _Next:fetch: 一个布尔型参数,默认为False:直接返回下一页的 url地址;       如果设置为True:则直接返回下一页的 HTML对象
这个方法我自己测试了一下,只有一些特定的网站才能实现这个功能,requests_html在的源码中可以看到,作者通过搜索包含'next', 'more', 'older'字段的a标签(因为一般情况下我们的下一页url就是在a标签下的href属性中),所以只有满足了他的条件才会实现这个功能(也就是说HTML页面不按照这个套路它就无法实现这个功能!),下面是部分源码
DEFAULT_NEXT_SYMBOL = ['next', 'more', 'older']# next()方法    def next(self, fetch: bool = False, next_symbol: _NextSymbol = DEFAULT_NEXT_SYMBOL) -> _Next:        """Attempts to find the next page, if there is one. If ``fetch``        is ``True`` (default), returns :class:`HTML <HTML>` object of        next page. If ``fetch`` is ``False``, simply returns the next URL.        """        def get_next():            candidates = self.find('a', containing=next_symbol) # 寻找 包含字段'next', 'more', 'older' 的a标签
这里我就不做举例了,大家可以自行去尝试!异步requests_html中还支持了异步功能requests_html是使用了asynico来封装了一些异步操作,所以这里的一些操作会用到asynico库相关的一些知识,如果您还不太了解,请自行学习!异步渲染JS前面我们介绍了使用render()方法渲染JS,其实它还支持异步渲染一般异步渲染使用在我们有多个页面需要进行渲染的情况下,因为只要在多任务的时候才能体现出异步的高效率,它有以下几个参数:
def __init__(self, loop=None, workers=None, mock_browser: bool = True, *args, **kwargs):loop: 使用的Asyncio循环。workers: 用于执行异步调用的线程数量。如果不传递,它将默认为电脑处理器数量乘以5
更多的异步使用方法请参考asyncio库的使用方法,下面是一个官方示例
>>> async def get_pyclock():...     r = await asession.get(';)...     await r.html.arender()...     return r...>>> results = asession.run(get_pyclock, get_pyclock, get_pyclock) # 这里作者将同一个页面使用异步方式进行了3次渲染,但是实际上使用的时间并不是平时的3倍!可能只是比平时渲染一个页面多花了一点时间而已!这就是异步的好处!
注意:results是一个列表异步传参这里是后面加的内容,因为我突然想到有时候我们的函数有可能是带参数的,那么这个时候我们可以使用lambda来进行传参,看下面示例
#!/usr/bin/env python# -*- encoding: utf-8 -*-                            # @Author     : xiao qiang# @WeChat     : xiaoqiangclub                              # @Software   : PyCharm      # @File       : test002.py# @Time       : 2021/5/30 19:48from requests_html import AsyncHTMLSessionaSession = AsyncHTMLSession()async def test(tt, yy):    r = await aSession.get(';)    await r.html.arender()    print('-{}-{}-'.format(tt, yy))    return rret1 = aSession.run(lambda: test('1', 'a'))ret2 = aSession.run(lambda: test('2', 'b'))ret3 = aSession.run(lambda: test('3', 'c'))print(ret1)print(ret2)print(ret3)
注意:这里ret1/ret2/ret3都是列表运行结果上面的示例还可以这样写

#!/usr/bin/env python

# -*- encoding: utf-8 -*-

# @Author : xiao qiang

# @WeChat : xiaoqiangclub

# @Software : PyCharm

# @File : test002.py

# @Time : 2021/5/30 19:48

from requests_html import AsyncHTMLSession

aSession = AsyncHTMLSession()

async def test(tt, yy):

r = await aSession.get(';)

await r.html.arender()

print('-{}-{}-'.format(tt, yy))

return r

# ret1 = aSession.run(lambda: test('1', 'a'))

# ret2 = aSession.run(lambda: test('2', 'b'))

# ret3 = aSession.run(lambda: test('3', 'c'))

# print(ret1)

# print(ret2)

# print(ret3)

#

test_dict = {

'1': 'a',

'2': 'b',

'3': 'c'

}

tasks = [lambda i=i, y=y: test(i, y) for i, y in

test_dict.items()] # lambda传参误区参考文章:

ret = aSession.run(*tasks) # 注意前面有个 *,不可少!# 参考文章:

print(ret)

这里在使用lambda传参的时候可能会出现一个错误,可以参考文章解决!运行结果异步发送请求我们在做爬虫的时候,特别是大型爬虫的时候,需要对很多页面进行操作,或者说是需要发送很多请求,也就是需要进行很多IO操作。所以,使用异步发送请求能显著地提升我们的爬虫效率!requests_html模块中,设置了一个AsyncHTMLSession类来实现发送异步请求,下面是一个官方示例

>>> from requests_html import AsyncHTMLSession>>> asession = AsyncHTMLSession()>>> async def get_pythonorg():...     r = await asession.get(';)...     return r...>>> async def get_reddit():...    r = await asession.get(';)...    return r...>>> async def get_google():...    r = await asession.get(';)...    return r...>>> results = asession.run(get_pythonorg, get_reddit, get_google)>>> results # check the requests all returned a 200 (success) code[<Response [200]>, <Response [200]>, <Response [200]>]>>> # Each item in the results list is a response object and can be interacted with as such>>> for result in results:...     print(result.html.url)...
上面的示例用到了asynico库中一些相关的知识,如果您还不太了解,请自行学习!总结requests_html模块requests库的基础上封装了页面解析数据清理的功能,并且添加了对当前比较流行的异步操作,让我们在做爬虫项目(一般项目)的时候无需再去使用多个第三方模块来实现功能,几乎是提供了一站式的服务!所以Python写爬虫使用requests_html就对了!(当然大项目还是首选scrapy,个人愚见!)更多内容视频讲解源码
from requests_html import HTMLSession, HTML, AsyncHTMLSessionfrom pprint import pprintclass DouBanTest:    def __init__(self):        self.start_url = ';  # 豆瓣电影排行榜url        self.js_url = ';        self.session = HTMLSession()  # 实例化session        self.aSession = AsyncHTMLSession()  # 实例化异步session        self.headers = {            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'        }    def get_response(self, url):        """获取响应,并返回requests_html中的HTML对象"""        r = self.session.get(url, headers=self.headers)        # print(r)        return r.html    # 快速获取页面中的url    def fast_get_urls(self):        """快速获取页面中的url"""        html = self.get_response(self.start_url)        # HTML的 links属性 可以快速获取到页面中 a标签中的href属性        urls = html.links        # pprint(urls)        # HTML的 absolute_links属性 可以快速获取到页面中 a标签中的href属性,并返回绝对url地址        absolute_urls = html.absolute_links        pprint(absolute_urls)    # 清洗数据(提取数据)    def get_data_by_xpath(self):        """使用xpath获取数据"""        html = self.get_response(self.start_url)        a_list = html.xpath('//table//div/a')        # pprint(a_list)        # 提取它的标题和url        movies_info = dict()        for a in a_list:            title = a.text  # 获取标题(文本)            # print(title)            movie_url = a.attrs.get('href')  # 使用 attrs 来解析element元素,并获得一个字典            # print(movie_url)            # print('-----')            movies_info[title] = movie_url        pprint(movies_info)    # 清洗数据(提取数据)    def get_data_by_css(self):        """使用css获取数据"""        html = self.get_response(self.start_url)        a_list = html.find('tr[class="item"] div a')  # 参考 css选择器 语法        # pprint(a_list)        # 提取它的标题和url        movies_info = dict()        for a in a_list:            title = a.text  # 获取标题(文本)            # print(title)            movie_url = a.attrs.get('href')  # 使用 attrs 来解析element元素,并获得一个字典            # print(movie_url)            # print('-----')            movies_info[title] = movie_url        pprint(movies_info)    # 清洗数据(提取数据)    def get_data_by_re(self):        """使用css获取数据"""        html = self.get_response(self.start_url)        # search() 获取第一条匹配的数据        # first_url = html.search('a href="{}"')  # 参数可以参考正则,获取第一条匹配的数据        # pprint(first_url)        # search_all() 获取所有满足条件的数据列表        # url_list = html.search_all('a h{}f="{}"')        url_list = html.search_all('a h{title}f="{url}"')  # 对取值方式进行命名,返回一个列表        # pprint(url_list)        #        # 提取数据        for url in url_list:            print(url)            print(url['title'])  # 使用 result[name] 进行取值            print(url['url'])            # print(url[0])            # print(url[1])            print('----------')    # HTML类    def use_HTML(self):        """使用HTML模块处理文档"""        html_str = '<a class="nbg" href="; title="活死人军团">'        html = HTML(html=html_str)        # links        print(html.links)        # search()        print(html.search('href="{}"'))    # 加载JS页面    def load_js(self):        html = self.get_response(self.js_url)        # 使用一个 render()方法 来加载js(实际上使用这个pyppeteer)        # html.render(wait=3)  # js加载        print(html.html)    async def send_requests_ues_async(self, url):        """发送异步请求"""        """获取响应,并返回requests_html中的HTML对象"""        r = await self.aSession.get(url, headers=self.headers)        # print(r)        return r.html    def get_response_by_async(self):        url_list = [            ';,            ';,            ';,        ]        tasks = [lambda url=url: self.send_requests_ues_async(url) for url in url_list]        ret = self.aSession.run(*tasks)  # 返回的是一个HTML对象列表        # print(ret)        # print(ret[0].html)        for html in ret:            print(html)    async def load_js_use_async(self, url):        """异步加载js"""        html = await self.send_requests_ues_async(url)        # 异步加载js        await html.arender()        return html    def get_js_by_async(self):        # ret = self.aSession.run(self.load_js_use_async)        #        # print(ret[0].html)        url_list = [            ';,            ';,            ';,        ]        tasks = [lambda url=url: self.load_js_use_async(url) for url in url_list]        ret = self.aSession.run(*tasks)  # 返回的是一个HTML对象列表        # print(ret)        # print(ret[0].html)        for html in ret:            print(html)if __name__ == '__main__':    test = DouBanTest()    # test.get_data_by_xpath()    # test.get_data_by_css()    # test.fast_get_urls()    # test.get_data_by_re()    # test.use_HTML()    # test.load_js()    # test.get_response_by_async()    test.get_js_by_async()

【本文由 "XiaoqiangClub" 发布,2021年6月17日】

标签: #html获取object #js左右翻页