【Python技能树共建】requests-html库初识_requests_html-程序员宅基地

技术标签: python技能树  python  Python入门  精彩技术文  python技能树共建  开发语言  

requests-html 模块是什么

requests-html 模块安装使用 pip install requests-html 即可,官方手册查询地址:requests-html.kennethreitz.org/,官方并没有直接的中文翻译,在检索过程中,确实发现了一版中文手册,在文末提供。

先看一下官方对该库的基本描述:

  • Full JavaScript support!(完全支持 JS,这里手册还重点标记了一下,初学阶段可以先忽略)
  • CSS Selectors (a.k.a jQuery-style, thanks to PyQuery).(集成了 pyquery 库,支持 css 选择器)
  • XPath Selectors, for the faint at heart.(支持 XPath 选择器)
  • Mocked user-agent (like a real web browser).(mock UA 数据,这点不错)
  • Automatic following of redirects.(自动跟踪重定向)
  • Connection–pooling and cookie persistence.(持久性 COOKIE)
  • The Requests experience you know and love, with magical parsing abilities.(额,这最后一点,各位自己领悟吧)

Only Python 3.6 is supported. 仅支持 Python 3.6 ,实测发现 3.6 以上版本依旧可以。

对于该库的简单使用,代码如下所示:

from requests_html import HTMLSession
session = HTMLSession()

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

print(r)

首先从 requests_html 库导入 HTMLSession 类,然后将其实例化之后,调用其 get 方法,发送请求,得到的 r 输出为 <Response [200]>,后续即可使用内置的解析库对数据进行解析。

由于该库是解析 html 对象,所以可以查看对应的 html 对象包含哪些方法与与属性。

通过 dir 函数查阅。

print(dir(r.html))
# 输出如下内容:
['__aiter__', '__anext__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__',
'__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__weakref__', '_async_render', '_encoding', '_html', '_lxml', '_make_absolute', '_pq', 'absolute_links', 'add_next_symbol',
'arender', 'base_url', 'default_encoding', 'element', 'encoding', 'find', 'full_text', 'html', 'links', 'lxml', 'next',
'next_symbol', 'page', 'pq', 'raw_html', 'render', 'search', 'search_all', 'session', 'skip_anchors', 'text', 'url', 'xpath']

该函数只能输入大概内容,细节还是需要通过 help 函数查询,例如:

html 对象的方法包括

  • find:提供一个 css 选择器,返回一个元素列表;
  • xpath:提供一个 xpath 表达式,返回一个元素列表;
  • search: 根据传入的模板参数,查找 Element 对象;
  • search_all:同上,返回的全部数据;

html 对象的属性包括

  • links:返回页面所有链接;
  • absolute_links:返回页面所有链接的绝对地址;
  • base_url:页面的基准 URL;
  • htmlraw_htmltext:以 HTML 格式输入页面,输出未解析过的网页,提取页面所有文本;

有了上述内容铺垫之后,在进行 Python 爬虫的编写就会变的容易许多,requests-html 库将通过 3~4 个案例进行学习掌握,接下来进入第一个案例。

怎么用

目标站点分析

本次要采集的目标网站为:www.world68.com/top.asp?t=5star&page=1,目标站点描述为【全球名站】。
requests-html库初识 + 无资料解BUG之 I/O error : encoder error,Python爬虫第30例
在获取数据源发送请求前,忽然想起可以动态修改 user-agent,查阅该库源码发现,它只是使用了 fake_useragent 库来进行操作,并无太神奇的地方,所以可用可不用该内容。

DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8'

def user_agent(style=None) -> _UserAgent:
    """Returns an apparently legit user-agent, if not requested one of a specific
    style. Defaults to a Chrome-style User-Agent.
    """
    global useragent
    if (not useragent) and style:
        useragent = UserAgent()

    return useragent[style] if style else DEFAULT_USER_AGENT

其余内容相对比较简单,页码规则如下:

www.world68.com/top.asp?t=5star&page=1
www.world68.com/top.asp?t=5star&page=2

累计页数直接在底部进行了展示,可以设计为用户手动输入,即 input 函数实现。

目标数据存储网站名网站地址即可,基于此,开始编码。

编码时间

首先通过单线程实现 requests-html 的基本逻辑,注意到下述代码非常轻量,

from requests_html import HTMLSession

session = HTMLSession()

page_size = int(input("请输入总页码:"))
for page in range(1, page_size + 1):

    world = session.get(f'http://www.world68.com/top.asp?t=5star&page={
      page}')
    world.encoding = 'gb2312'
    # world.html.encoding = "gb2312"
    # print(world.text)
    print("正在采集数据", world.url)
    title_a = world.html.find('dl>dt>a')
    for item in title_a:
        name = item.text
        url = item.attrs['href']
        with open('webs.txt', "a+", encoding="utf-8") as f:
            f.write(f"{
      name},{
      url}\n")

上述代码重点部分说明如下:

  • world.encoding,设置了网页解析编码;
  • world.html.find('dl>dt>a') 通过 css 选择器,查找所有的网页标题元素;
  • item.text 提取网页标题内容;
  • item.attrs['href'] 获取元素属性,即网站域名。

运行效果如下所示,获取到的 3519 个站点,就不在提供了,简单运行 1 分钟代码,即可得到。
requests-html库初识 + 无资料解BUG之 I/O error : encoder error,Python爬虫第30例
由于上述代码太少了,完全不够今日代码量,我们顺手将其修改为多线程形式。

import requests_html
import threading
import time
import fcntl


class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global page, lock, page_size
        while True:
            lock.acquire(True)
            if page >= page_size:
                lock.release()
                break
            else:
                page += 1
                lock.release()
                requests_html.DEFAULT_ENCODING = "gb18030"
                session = requests_html.HTMLSession()

                print("正在采集第{}页".format(page), "*" * 50)
                try:
                    page_url = f'http://www.world68.com/top.asp?t=5star&page={
      page}'
                    world = session.get(page_url, timeout=10)
                    print("正在采集数据", world.url)
                    # print(world.html)
                    title_a = world.html.find('dl>dt>a')
                    print(title_a)
                    my_str = ""

                    for item in title_a:
                        name = item.text
                        url = item.attrs['href']
                        my_str += f"{
      name.encode('utf-8').decode('utf-8')},{
      url}\n"

                    with open('thread_webs.txt', "a+", encoding="utf-8") as f:
                        fcntl.flock(f.fileno(), fcntl.LOCK_EX)  # 文件加锁
                        f.write(f"{
      my_str}")

                except Exception as e:
                    print(e, page_url)


if "__main__" == __name__:
    page_size = int(input("请输入总页码:"))
    page = 0
    thread_list = []

    # 获取开始时间
    start = time.perf_counter()

    lock = threading.Lock()
    for i in range(1, 5):
        t = MyThread()
        thread_list.append(t)
    for t in thread_list:
        t.start()
    for t in thread_list:
        t.join()
    # 获取时间间隔
    elapsed = (time.perf_counter() - start)
    print("程序运行完毕,总耗时为:", elapsed)

在正式进行编码之后,发现存在比较大的问题,编码问题,出现如下错误:

encoding error : input conversion failed due to input error, bytes 0x81 0xE3 0xD3 0xAA
encoding error : input conversion failed due to input error, bytes 0x81 0xE3 0xD3 0xAA
encoding error : input conversion failed due to input error, bytes 0x81 0xE3 0xD3 0xAA
I/O error : encoder error

该错误在执行单线程时并未发生,但是当执行多线程时,异常开始出现,本问题在互联网上无解决方案,只能自行通过 requests-html 库的源码进行修改。

打开 requests_html.py 文件,将 417 行左右的代码进行如下修改:

def __init__(self, *, session: Union['HTMLSession', 'AsyncHTMLSession'] = None, url: str = DEFAULT_URL, html: _HTML, default_encoding: str = DEFAULT_ENCODING, async_: bool = False) -> None:
	# 修改本部分代码
    # Convert incoming unicode HTML into bytes.
    # if isinstance(html, str):
    html = html.decode(DEFAULT_ENCODING,'replace')

    super(HTML, self).__init__(
        # Convert unicode HTML to bytes.
        element=PyQuery(html)('html') or PyQuery(f'<html>{
      html}</html>')('html'),
        html=html,
        url=url,
        default_encoding=default_encoding
    )

代码 if isinstance(html, str): 用于判断 html 是否为 str,但是在实测过程中发现 html<class 'bytes'> 类型,所以数据没有进行转码工作,故取消相关判断。

除此以外,通过输出 world.html.encoding 发现网页的编码不是 GB2312 ,而是 gb18030,所以通过下述代码进行了默认编码的设置。

requests_html.DEFAULT_ENCODING = "gb18030"

按照如上内容进行修改之后,代码可以正常运行,数据能正确的采集到。

本案例还新增了代码运行时长的计算,具体如下:

# 获取开始时间
start = time.perf_counter()
# 执行代码的部分
# 获取时间间隔
elapsed = (time.perf_counter() - start)
print("程序运行完毕,总耗时为:", elapsed)

完整的代码运行效果如下所示:

requests-html库初识 + 无资料解BUG之 I/O error : encoder error,Python爬虫第30例

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hihell/article/details/124608636

智能推荐

python下载安装教程_python官网下载安装-程序员宅基地

文章浏览阅读10w+次,点赞178次,收藏486次。python3.7.3下载步骤第一步:进入Python官网[https://www.python.org/](https://www.python.org/)第二步:点击downloads进入下载界面选择你想要的下载的版本。这里我选择的是Python3.7.3第三步:新建一个标签,输入网址:[https://python123.io/download](https://python123.io/d..._python官网下载安装

【SVM回归预测】基于鹈鹕算法优化卷积神经网络结合支持向量机实现POA-CNN-SVM实现数据回归预测附matlab代码-程序员宅基地

文章浏览阅读893次,点赞19次,收藏20次。本文提出了一种基于鹈鹕算法优化卷积神经网络结合支持向量机(POA-CNN-SVM)的数据回归预测方法。该方法首先利用鹈鹕算法优化卷积神经网络的参数,然后将优化后的卷积神经网络与支持向量机相结合,构建POA-CNN-SVM回归模型。最后,利用POA-CNN-SVM回归模型对数据进行回归预测。实验结果表明,该方法能够有效提高数据回归预测的准确性。

选项菜单的一些基本内容_android:icon参数是id-程序员宅基地

文章浏览阅读280次。菜单的分类第一种菜单在Activity中的创建OptionMenu的方法,这个方法需要我们自行覆盖,getMenu Inflater()这个方法返回一个MenuInflate对象,这个对象下面有inflate()方法,这个方法需要传两个值,第一个是我们的menu资源,传他的资源索引就可以了,第二个参数就是我们的菜单对象,但是我们的菜单对象早就通过onCreateOptionsMenu方法传进来了,即menu,这个方法就可以将我们的菜单资源加载到页面上,而return 后面应该_android:icon参数是id

ubuntu10.10安装TFTP-程序员宅基地

文章浏览阅读2k次。/*ubuntu10.10安装TFTP*/sudo mkdir /tftpbootsudo chmod 777 /tftpbootsudo apt-get install tftp /*安装客户端*/sudo apt-get install tftpd /*安装服务器端*/sudo apt-get install openbsd-inetdsudo vi /etc/inetd.conf在最后加入一行:tftp dgram udp wait nobody /usr/sbin/tcpd /usr/

【交通标志识别】基于SIFT特征实现交通标志识别matlab源码含GUI-程序员宅基地

文章浏览阅读323次。一、简介SIFT即尺度不变特征变换,是用于图像处理领域的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。\1 SIFT算法特点:\(1)具有较好的稳定性和不变性,能够适应旋转、尺度缩放、亮度的变化,能在一定程度上不受视角变化、仿射变换、噪声的干扰。\(2)区分性好,能够在海量特征数据库中进行快速准确的区分信息进行匹配\(3)多量性,就算只有单个物体,也能..._交通要素识别算法

Educational Codeforces Round 111 (Rated for Div. 2)-程序员宅基地

文章浏览阅读124次。Problem - A - CodeforcesCodeforces. Programming competitions and contests, programming communityhttps://codeforces.com/contest/1550/problem/A签到:B. Maximum Cost Deletion题意:给你一个01字符串,我们每次可以删除相连的且内部每个字符都相等的子串.每次删除的长度为l,那么对于答案的贡献就是a*l+b,a和b都是需要进行输入的.问最大贡献_educational codeforces round 111 (rated for div. 2)

随便推点

要被淘汰的程序猿-程序员宅基地

文章浏览阅读74次。今天小伙伴都比较忙,我去修改了一个程序的bug搞了至少20分钟,居然被一个以前不care的小问题难住了。jquery span 用 $(".ybm").val() 无法获取到值,$(".ybm").text()才可以获取到值 文本输入框用$(".ybm").val()谨记...

Java源码分析之HashMap(JDK1.8)_hashmap key是如何算出hsahcode的-程序员宅基地

文章浏览阅读8.9k次,点赞10次,收藏30次。一、HashMap概述HashMap是常用的Java集合之一,是基于哈希表的Map接口的实现。与HashTable主要区别有不支持同步和允许null作为key和value。由于HashMap不是线程安全的,如果想要线程安全,可以使用ConcurrentHashMap代替。二、HashMap数据结构HashMap的底层是哈希数组,数组元素为Entry。HashMap通过key的has_hashmap key是如何算出hsahcode的

HTML5常用标签及属性_html5标签属性大全-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏31次。HTML常用标记一、文本标记1.标题标记2.字体标记一、文本标记1.标题标记标题标记的语法格式:<hn align="对齐方式">标题文本</hn><!--HTML中提供了6级标题,为<h1>至<h6>,其中<h1>最大,<h6>最小n代表1,2,3,4,5,6align属性有三种,分别是:left(左对齐),center(居中),right(右对齐)-->例子:<body> <_html5标签属性大全

查找薪水涨幅超过15次的员工号emp_no以及其对应的涨_查找薪水涨幅超过10次的员工-程序员宅基地

文章浏览阅读163次。题目描述查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数tCREATE TABLE `salaries` (`emp_no` int(11) NOT NULL,`salary` int(11) NOT NULL,`from_date` date NOT NULL,`to_date` date NOT NULL,PRIMARY KEY (`emp_no`,`from_date`));s..._查找薪水涨幅超过10次的员工

java程序入门基本_int=2,int h=3-程序员宅基地

文章浏览阅读548次。1、基本操作import java.math.BigDecimal;import java.math.BigInteger;public class hello { public static voidmain(String[] args){ System.out.print("hello"); //输出 byteb=127; _int=2,int h=3

推荐文章

热门文章

相关标签