摘要:目标站点分析本次要采集的目标网站为,目标站点描述为全球名站。由于上述代码太少了,完全不够今日代码量,我们顺手将其修改为多线程形式。
本篇博客是《爬虫 120 例》的第 30 例,新学习一个爬虫框架 requests-html
,该框架作者就是 requests
的作者,所以盲猜就很好用啦。
requests-html
模块安装使用 pip install requests-html
即可,官方手册查询地址:https://requests-html.kennethreitz.org/,官方并没有直接的中文翻译,在检索过程中,确实发现了一版中文手册,在文末提供。
先看一下官方对该库的基本描述:
Only Python 3.6 is supported. 仅支持 Python 3.6 ,实测发现 3.6 以上版本依旧可以。
对于该库的简单使用,代码如下所示:
from requests_html import HTMLSessionsession = HTMLSession()r = session.get("https://python.org/")print(r)
首先从 requests_html
库导入 HTMLSession
类,然后将其实例化之后,调用其 get
方法,发送请求,得到的 r
输出为
,后续即可使用内置的解析库对数据进行解析。
由于该库是解析 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;html
,raw_html
,text
:以 HTML 格式输入页面,输出未解析过的网页,提取页面所有文本;有了上述内容铺垫之后,在进行 Python 爬虫的编写就会变的容易许多,requests-html
库将通过 3~4 个案例进行学习掌握,接下来进入第一个案例。
本次要采集的目标网站为:http://www.world68.com/top.asp?t=5star&page=1,目标站点描述为【全球名站】。
在获取数据源发送请求前,忽然想起可以动态修改 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
其余内容相对比较简单,页码规则如下:
http://www.world68.com/top.asp?t=5star&page=1http://www.world68.com/top.asp?t=5star&page=2
累计页数直接在底部进行了展示,可以设计为用户手动输入,即 input
函数实现。
目标数据存储网站名与网站地址即可,基于此,开始编码。
首先通过单线程实现 requests-html
的基本逻辑,注意到下述代码非常轻量,
from requests_html import HTMLSessionsession = 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 分钟代码,即可得到。
由于上述代码太少了,完全不够今日代码量,我们顺手将其修改为多线程形式。
import requests_htmlimport threadingimport timeimport fcntlclass 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 0xAAencoding error : input conversion failed due to input error, bytes 0x81 0xE3 0xD3 0xAAencoding error : input conversion failed due to input error, bytes 0x81 0xE3 0xD3 0xAAI/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, url=url, default_encoding=default_encoding )
代码 if isinstance(html, str):
用于判断 html
是否为 str
,但是在实测过程中发现 html
是
类型,所以数据没有进行转码工作,故取消相关判断。
除此以外,通过输出 world.html.encoding
发现网页的编码不是 GB2312
,而是 gb18030
,所以通过下述代码进行了默认编码的设置。
requests_html.DEFAULT_ENCODING = "gb18030"
按照如上内容进行修改之后,代码可以正常运行,数据能正确的采集到。
本案例还新增了代码运行时长的计算,具体如下:
# 获取开始时间start = time.perf_counter()# 执行代码的部分# 获取时间间隔elapsed = (time.perf_counter() - start)print("程序运行完毕,总耗时为:", elapsed)
完整的代码运行效果如下所示:
代码仓库地址:https://codechina.csdn.net/hihell/python120,去给个关注或者 Star 吧。
数据没有采集完毕,想要的可以在评论区留言交流
今天是持续写作的第 212 / 365 天。
可以关注我,点赞我、评论我、收藏我啦。
更多精彩
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/119409.html
摘要:爬虫实战一使用和,我们使用了做网络请求,拿到网页数据再用解析,就在前不久,作者出了一个新库,,它可以用于解析文档的。是基于现有的框架等库进行了二次封装,更加方便开发者调用。参考今天用了一下库爬虫公众号我的公众号吴小龙同学,欢迎交流 Python 爬虫实战(一):使用 requests 和 BeautifulSoup,我们使用了 requests 做网络请求,拿到网页数据再用 Beaut...
摘要:提升倍虽是我胡诌的数据,开发效率的提升却是杠杠滴。而却不同,它提供了官方中文文档,其中包括了很清晰的快速上手和详尽的高级用法和接口指南。其他更多详细内容不多说了,中文官网地址,顺着看一遍,写一遍,你就掌握这个爬虫神器了。 他叫 Kenneth Reitz。现就职于知名云服务提供商 DigitalOcean,曾是云计算平台 Heroku 的 Python 架构师,目前 Github 上 ...
阅读 1372·2021-11-24 09:39
阅读 3669·2021-11-24 09:39
阅读 1842·2021-11-16 11:54
阅读 1428·2021-09-30 09:47
阅读 1680·2021-09-26 10:16
阅读 2325·2021-09-22 15:33
阅读 1428·2021-09-14 18:01
阅读 2405·2021-09-07 09:59