Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >爬虫工具_应用程序market

爬虫工具_应用程序market

作者头像
全栈程序员站长
发布于 2022-11-18 03:26:52
发布于 2022-11-18 03:26:52
51500
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

一个简单的异步爬虫.

私信太多,统一回答一下:

关于异步函数的:

1. 真正派发任务的是 consumer 这个coroutine,所以也在内部做了并发控制.

2. process_content 用于获取html及保存到mysql.

关于异步相关(asyncio)的 :

1.await 相当于 yield from .

2.await 后面是一个coroutine, 普通函数不是coroutine,普通函数也不是通过加一个 async / asyncio.coroutine,就能真正

成为coroutine的,就算没报错,如果内部加了阻塞函数(time.sleep / read /write ) 还是一个阻塞函数;因此,往往我们自己的

coroutine只是一个中间层的东西,所以需要aiohttp , aiomysql等这个模块来提供支持,就跟tornado的异步框架一样,如果你

在get()/post() 中加了阻塞函数调用,tornado 还是阻塞的.

3. 这个问题问的有点多 .

1. await 后面可以是 Task,Future,async def xxx() ( 自定义函数) ,因此在加入loop 时,将自动封装我们自定义的coroutine成为一个 Task / Future 对象.

* 2. 无论是 await 还是 asyncio.ensure_future/async , 都将把coroutine加入loop中,但是两者有一个差别:

await 是等待这个coroutine 运行完成, ensure_future/async 不会等待直接仍入循环体中运行.

这个就是下面代码中一会用await 一会用ensure_future/async .同样的也是很多人问,

为什么在控制 coroutine 的时候: async with sem 后面用ensure_future 控制不了的原因

3.额外说明一下Future对象. 下面代码中没有自行创建Future对象, 其实也可以用, Future对象与Twisted中的

Defer对象极其类似. 只不过Future 对象一般都是 await Future, 当然也可以使用回调: Future.add_done_callback.

而Defer对象是使用2个回调链的方式.具体可参考我写的:Twisted

这2个对象都在Future.set_result / Defered.callbacks “返回”执行 await Future之后的代码 / Deferred 中的无穷无尽的callbacks.

关于Future对象的运行流程可看官方文档或Tornado中的 AsyncHTTPClient.fetch.

下面给一个Tornado中使用Future对象的案例 : 注意,没有使用过Tornado协程的别看了, Tornado旧版本的协程有些误导

1.第一个使用Future对象的Tornado案例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class cor(RequestHandler):
   @gen.coroutine  #tornado 装饰器
   def get(self):
        #创建一个异步客户端
        clt = AsyncHTTPClient()
        #fetch 将返回一个Future对象 . yield 这个Future,直到set_result被调用
        res = yield clt.fetch('http://www.baidu.com')
        print('fetch : ' , res)
        self.write(res.body)

2.这个案例比较容易理解, 使用了新的语法,与下面爬虫的协程语法一致

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class cor(RequestHandler):
   async def get(self): #用了新的语法
        clt = AsyncHTTPClient()

        #使用了await Future,直到 Future.set_result 被调用
        res = await clt.fetch('http://www.baidu.com')
        print('fetch : ' , res)
        self.write(res.body)

分割线:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import asyncio
import aiohttp
from lxml import etree
import aiomysql
import re
#一些全局变量
start_url = "http://www.jobbole.com/"
waitting_urls = None
visited_urls = set()
failed_urls = set()
stop_fetch = False
USER_AGENT_LIST = [
'MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',
'Opera/9.20 (Macintosh; Intel Mac OS X; U; en)',
'Opera/9.0 (Macintosh; PPC Mac OS X; U; en)',
'iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)',
'Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)',
'iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20120813 Firefox/16.0',
'Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)',
'Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)',
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"
]
import random
#控制corroutine数量
sem = asyncio.Semaphore(4)
#获取html
async def fetch(session, url):
headers = {'User-Agent' : random.choice(USER_AGENT_LIST)}
try:
#单一一个站点用一个会话就行了
async with session.get(url,headers=headers) as r:
#已经访问过的url
visited_urls.add(url)
print("url:{} status:{}".format(url,r.status))
#获取结果,await / yield from (如果用asyncio.coroutine)
text = await r.text(encoding='utf8')
return text
except Exception as e:
print('url:{} failed')
failed_urls.add(url)
return None
#获取mysql pool . 自己看文档把,文档里写的很清楚
async def get_mysql_pool(**settings):
pool = await aiomysql.create_pool(**settings)
return pool
#获取href属性
def extract_urls(html):
htmlobj = etree.HTML(html)
return set(htmlobj.xpath('//a[contains(@href,"http")]/@href'))
#获取标题
def get_title(html):
htmlobj = etree.HTML(html)
title = ''.join(htmlobj.xpath('//div[@class="entry-header"]/h1/text()'))
return title
#处理数据,保存到mysql
async  def process_content(session,url,pool):
#获取html
html = await fetch(session, url)
#深度控制,我这就获取一层
# urls = extract_urls(html) 深度控制,这里不做了
sql = 'insert into jobbole(title) VALUES(%s)'
title = get_title(html)
#获取pool中的连接
async with pool.acquire() as conn:
#拿游标
async with conn.cursor() as cur:
try:
await cur.execute(sql,(title))
await conn.commit()
except Exception as e:
await conn.rollback()
print(e)
#额,这个名字随意取了一个,相当于消费者.申明啊,这个函数我就随意一写,没调式过.
async def consumer(session,pool):
#只要waitting_urls不为空,就拿出来,去获取内容
while not stop_fetch:
while len(waitting_urls) == 0 and not stop_fetch:
#如果空了,休息一下
await asyncio.sleep(1)
continue
if len(waitting_urls) > 0 :
url = waitting_urls.pop()
#这里就拿个标题,只要符合的就ok.
if re.match('https?://.*?jobbole.com/\d+/',url) and url not in visited_urls:
#做一下控制并发
async with sem:
#这行注释掉,否则就别用控制并发了
# asyncio.ensure_future(process_content(session,url,pool))
await process_content(session,url,pool)
#一开始的准备工作, 我这里只从首页拿所有的url
async def prepare_urls(session):
global waitting_urls
html = await fetch(session, start_url)
urls = extract_urls(html)
waitting_urls = {url for url in urls}
print('waitinglist len:' , len(waitting_urls))
#一个检测函数
async def check_tasks():
while True:
print('当前运行corotine数量 :' , len(asyncio.Task.all_tasks()))
await asyncio.sleep(0.5)
async def main(**settings):
#创建sess
session = aiohttp.ClientSession()
#创建mysql pool
pool = await get_mysql_pool(**settings)
#开启检测
asyncio.ensure_future(check_tasks())
#准备首页的所有url
await prepare_urls(session)
#开始运行这个coroutine ,真正干活的
asyncio.ensure_future(consumer(session,pool))
#关闭用的,这里没用到, 可以自行修改添加
async def close(session,pool):
await session.close()
pool.close()
await pool.wait_closed()
#拿主循环
lp = asyncio.get_event_loop()
#mysql配置
db_mysql_settings = {
'db' : 'testdb',
'host' : '127.0.0.1',
'port' : 3306,
'user' : 'root',
'password' : 'fuck',
'loop' : lp,
'charset' : 'utf8',
'maxsize':50
}
#开始运行
asyncio.ensure_future(main(**db_mysql_settings))
lp.run_forever()

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/210149.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年10月25日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【干货原创】介绍一个效率爆表的数据采集框架
今天我们来聊一下如何用协程来进行数据的抓取,协程又称为是微线程,也被称为是用户级线程,在单线程的情况下完成多任务,多个任务按照一定顺序交替执行。
用户6888863
2022/04/13
5510
【干货原创】介绍一个效率爆表的数据采集框架
Python爬虫模拟登陆和异步爬虫
模拟登陆 使用超级鹰平台识别验证码的编码流程: 将验证码图片进行本地下载 调用平台提供的示例代码进行图片数据识别 有验证码,验证码可以读取到但测试未成功 # 验证码 import requests from lxml import html import chaojiying # 封装识别验证码函数 if __name__ == "__main__": headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win6
shaoshaossm
2022/12/26
4640
大规模异步新闻爬虫【6】:用asyncio实现异步爬虫
关于异步IO这个概念,可能有些小猿们不是非常明白,那就先来看看异步IO是怎么回事儿。 为了大家能够更形象得理解这个概念,我们拿放羊来打个比方:
一墨编程学习
2019/05/15
1.4K0
大规模异步新闻爬虫【6】:用asyncio实现异步爬虫
Python 异步爬虫原理解析及爬取实战
爬虫是 IO 密集型任务,比如我们使用 requests 库来爬取某个站点的话,发出一个请求之后,程序必须要等待网站返回响应之后才能接着运行,而在等待响应的过程中,整个爬虫程序是一直在等待的,实际上没有做任何的事情。
叶庭云
2022/05/08
8100
Python  异步爬虫原理解析及爬取实战
python︱用asyncio、aiohttp实现异步及相关案例
Asyncio 是并发(concurrency)的一种方式。对 Python 来说,并发还可以通过线程(threading)和多进程(multiprocessing)来实现。Asyncio 并不能带来真正的并行(parallelism)。当然,因为 GIL(全局解释器锁)的存在,Python 的多线程也不能带来真正的并行。 .
悟乙己
2019/05/26
2.3K0
【Python3爬虫】使用异步协程编写爬
进程:进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。进程是操作系统动态执行的基本单元。
py3study
2020/01/21
1.1K0
爬虫速度太慢?来试试用异步协程提速吧!
在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞。比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,程序一直在等待网站响应,最后导致其爬取效率是非常非常低的。
崔庆才
2018/07/31
2.9K0
Python爬虫学习笔记 asyncio+aiohttp 异步爬虫原理和解析
爬虫是 IO 密集型任务,比如如果我们使用 requests 库来爬取某个站点的话,发出一个请求之后,程序必须要等待网站返回响应之后才能接着运行,而在等待响应的过程中,整个爬虫程序是一直在等待的,实际上没有做任何的事情。
叶庭云
2020/09/17
3.8K0
Python爬虫学习笔记    asyncio+aiohttp 异步爬虫原理和解析
[译]Tornado协程
Tornado 4.3于2015年11月6日发布,该版本正式支持Python3.5的async/await关键字,并且用旧版本CPython编译Tornado同样可以使用这两个关键字,这无疑是一种进步。其次,这是最后一个支持Python2.6和Python3.2的版本了,在后续的版本了会移除对它们的兼容。现在网络上还没有Tornado4.3的中文文档,所以为了让更多的朋友能接触并学习到它,我开始了这个翻译项目,希望感兴趣的小伙伴可以一起参与翻译,项目地址是tornado-zh on Github,翻译好的文档在Read the Docs上直接可以看到。欢迎Issues or PR。
Jintao Zhang
2018/08/27
9070
Tornado入门(三)【协程】
在Tornado中,协程是推荐使用的异步方式。协程使用yield关键字暂停或者恢复执行,而不是回调链的方式。
用户2936342
2018/08/27
1.3K0
python爬虫–协程(初识)
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/100101.html原文链接:
全栈程序员站长
2021/04/19
5300
python爬虫–协程(初识)
python协程初体验
在了解了Python并发编程的多线程和多进程之后,我们来了解一下基于asyncio的异步IO编程 => 协程
测试加
2022/06/21
3910
python协程初体验
python进阶(17)协程「建议收藏」
协程(Coroutine),又称微线程,纤程。(协程是一种用户态的轻量级线程) 作用:在执行 A 函数的时候,可以随时中断,去执行 B 函数,然后中断B函数,继续执行 A 函数 (可以自动切换),但这一过程并不是函数调用(没有调用语句),过程很像多线程,然而协程只有一个线程在执行 通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定
全栈程序员站长
2022/09/19
1K0
【Python爬虫实战】深入理解Python异步编程:从协程基础到高效爬虫实现
随着网络和数据的迅速发展,越来越多的场景需要高效处理大量请求和数据。传统的同步编程模式在处理I/O密集型任务时会浪费大量等待时间,而Python的异步编程技术提供了一种更高效的方式。本文从Python异步编程的基础概念出发,深入讲解协程、asyncio库及其核心功能。通过详细的代码示例与解释,我们将逐步探索异步编程的应用场景
易辰君
2024/11/07
1500
python中重要的模块--asyncio
一直对asyncio这个库比较感兴趣,毕竟这是官网也非常推荐的一个实现高并发的一个模块,python也是在python 3.4中引入了协程的概念。也通过这次整理更加深刻理解这个模块的使用 asyncio 是干什么的? 异步网络操作 并发 协程 python3.0时代,标准库里的异步网络模块:select(非常底层) python3.0时代,第三方异步网络库:Tornado python3.4时代,asyncio:支持TCP,子进程 现在的asyncio,有了很多的模块已经在支持:aiohttp,aiodns
coders
2018/03/30
2.1K0
Python 的异步 IO:Asyncio 简介
所谓「异步 IO」,就是你发起一个 IO 操作,却不用等它结束,你可以继续做其他事情,当它结束时,你会得到通知。
IT派
2018/07/30
9550
用aiohttp和uvloop实现一个高性能爬虫
asyncio于Python3.4引入标准库,增加了对异步I/O的支持,asyncio基于事件循环,可以轻松实现异步I/O操作。接下来,我们用基于asyncio的库实现一个高性能爬虫。
周小董
2019/03/25
9070
用aiohttp和uvloop实现一个高性能爬虫
爬虫性能相关
根据文章内容撰写摘要总结。
coders
2018/01/04
5990
Python爬虫入门教程 7-100 蜂鸟网图片爬取之二
运行之后等待,安装完毕,想要深造,那么官方文档必备 :https://aiohttp.readthedocs.io/en/stable/
梦想橡皮擦
2019/02/13
5230
Python爬虫入门教程 7-100 蜂鸟网图片爬取之二
协程学习笔记
协程是轻量级线程,拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此协程能保留上一次调用时的状态,即所有局部状态的一个特定组合,每次过程重入时,就相当于进入上一次调用的状态。
somenzz
2020/12/10
6050
协程学习笔记
相关推荐
【干货原创】介绍一个效率爆表的数据采集框架
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验