V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
imn1
V2EX  ›  Python

懒,求个异步爬虫,必要需求是方便处理异常

  •  
  •   imn1 · 2020-05-11 14:10:53 +08:00 · 2670 次点击
    这是一个创建于 1658 天前的主题,其中的信息可能已经有所发展或是发生改变。
    速度、并发量不是最大需求,当然能做到更好

    必要的是出现爬取失败的 url,能扔进队列重试若干次
    持续失败( 403/404/50x,超时……等等)的能记录下来

    其次是可以自定义 header,包括 cookies 、UA 等等,当然包括可重用(session)

    搜了好几个简述都没这方面说明,估计不是逐个看文档,就是看代码……
    谁知道有这样的,省我一点时间,谢了
    16 条回复    2020-05-12 11:58:06 +08:00
    NaVient
        1
    NaVient  
       2020-05-11 14:21:35 +08:00
    开源不是伸手,别人没实现的你可以实现了提 PR 方便下一个朋友
    also24
        2
    also24  
       2020-05-11 14:30:22 +08:00 via Android
    第一行和第三行需求,直接 aiohttp 不就好了。

    第二行需求,自己用 redis 实现一下估计也就一百行以内?
    dayeye2006199
        3
    dayeye2006199  
       2020-05-11 14:35:09 +08:00   ❤️ 3
    这是传说中的伸手党?
    imn1
        4
    imn1  
    OP
       2020-05-11 14:52:18 +08:00
    @also24
    redis 我只认识这五个字母,🐶

    @NaVient
    伸手是伸手,但也不完全是拿来就用,肯定要自己改的
    只是年纪大了,又不是用来吃饭的东西,总不能我现在对某个软件不满意就重写一个,能尽量少改动最好

    爬虫十多年前就写过,单线程,但我较强能力在 parse (韩文以前我都爬过百多个站点),aio 或多线程方面很弱
    我以前玩的是 aria2 抓取,然后脚本 parse 出 link,导出 aria2 list,再重复几次到最后完成
    以前这样玩好处是主动操作,满足感强,现在只想扔到后台爬完整理就算了
    ruby0906
        5
    ruby0906  
       2020-05-11 15:14:56 +08:00
    要不是轮子太多,看楼主的描述我都想自己写一个。
    imn1
        6
    imn1  
    OP
       2020-05-11 15:23:01 +08:00
    @ruby0906 #5
    就是这个意思,如果自认为能力足够,已经动手了,我就从来没用过别人的 html parser 轮子
    问题是自己写出来的,自己用着都觉得糟心,还不如用人家高水平的轮子
    ClericPy
        7
    ClericPy  
       2020-05-11 15:51:45 +08:00
    以前还真写过类似的... https://github.com/ClericPy/torequests

    支持协程, 线程, 同步, 异步, 反正就是当年想在同步环境里享受到协程的高性能用的

    和原生 aiohttp 比, 损失 10% 性能, 带上 uvloop 损失 15% ~ 20%... 损失这么多现在我都有点不想用它了...

    https://paste.ubuntu.com/p/fFWsNmvVX2/ 简单的小例子
    tlemar
        8
    tlemar  
       2020-05-11 16:11:11 +08:00
    scrapy 可以满足需求
    imn1
        9
    imn1  
    OP
       2020-05-11 16:16:15 +08:00
    @ClericPy #7
    哎呀,失敬失敬,刚刚在看 torequests,没想到下一秒作者就出现了

    既然大驾光临,顺便问两个问题:
    1.我写个 class 继承 FailureException,就可以自行处理了吧,error 是 http error code 么?
    超时的 error 是什么,文档好像没写这个
    2.自定义 header 好像只见到 torequests.utils.curlparse(string, encoding='utf-8') ?
    ClericPy
        10
    ClericPy  
       2020-05-11 16:36:46 +08:00
    @imn1 #9

    1. FailureException 其实就是在 catch exception 的时候不抛错, 让它 Return 回来方便自省和排查, FailureException.error 实际就是原始抛出的错误

    另一方面 FailureException 主要作用就是存放了 request 的 kwargs, 方便回调的时候用上

    超时根据不同的依赖不一定是什么 error, 需要根据依赖来判断, aiohttp 或者 requests 里面都有很多细分, 超时也是区分了读超时和连接超时的, 所以得自己去他们源码里看看, 比如 requests.exceptions 里的 Timeout ConnectTimeout ReadTimeout, aiohttp 里面更复杂

    因此, 这里面的重试的涵盖范围默认是 aiohttp 和 requests 里面的请求错误的基类, 避免 handle 一些非请求类错误 (早年间因为 handle 了 KeyboardInterrupt 导致我一个十万请求的脚本差点停不下来...

    2. 没看懂自定义 Headers 是什么需求, 有个例子么. 可重用 Session 是默认的, tPool Requests 类都是只用一个 Client Session

    3. 代码一开始是刚上班时候自己边学边折腾的, 实际没什么有价值的地方, 不如自己现写一个 wrapper...
    imn1
        11
    imn1  
    OP
       2020-05-11 16:56:31 +08:00
    @ClericPy #10
    自定义 header,例如 UA 用 firefox/chrome...,cookies 增加一些条文,如页面访问点击“同意”,cookies 会多了 agree=1 这样,程序首次访问 cookies 没有这条或者 agree=0,后面用代码添加上去才能访问后面的页面

    我本来是想 requests 写个单函数,然后多进程执行,感觉放后台跑有点重,所以才找找有什么异步协程的,这样静默运行不影响我干其他事,所以能记录下载失败反而是最关键的
    crella
        12
    crella  
       2020-05-11 17:02:38 +08:00
    楼主自己的 html parser 的其中比较好的几个可以给个链接吗?想看看是怎么解析 html 的。谢谢
    ClericPy
        13
    ClericPy  
       2020-05-11 17:08:49 +08:00
    @imn1 #11 这些自然是带的, torequests 要做的就是兼容 Requests 的参数...

    req = tPool()
    task = req.get('http://httpbin.org', headers={"Cookie": "agree=0;"})
    resp = task.x

    这些都是 Requests 库原生的参数

    记录下载失败, 拿到结果以后如果是错误, FailureException 对象的 bool 都是 false 的, 而且也有 self.ok 来兼容 Requests 的响应, 所以只要判断 self.ok 就能知道请求是否成功了. Requests 的 Response.ok 判断的好像是状态码在 range(200, 300) 之间

    记录下载失败, 写个 Callback 函数做变量塞上应该就够了, lambda r: r.ok or open('file.txt', 'a').write('xxx')
    imn1
        14
    imn1  
    OP
       2020-05-11 17:34:09 +08:00
    @crella #12
    没公布,而且有些年头,这次也要重写
    没什么特别,就是正则用得好而已(我不需要 bs4/lxml )
    加两三个函数,可以根据捕获"last page"生成一个组合 list,也就是 itertools.product()之类
    有个函数是处理,分散在几个页面的信息,要各自取出合成一个 record,外面的框架很少见有做这个,但这个只是业务逻辑理顺,跟代码能力无关
    可以导出 aria2/wget 可用的 list,wget 不能指定输出文件名,加个下载后对照改名的脚本
    ……

    总的一句,就是做了一个 py,然后不同站点写个 ini/cfg/yaml 什么的,把一堆正则、referrer 按顺序扔进去,就能跑,仅此而已,没什么特别,比别人强的地方可能就是我熟悉中日韩 unicode 字符,文字处理比人家写的要简洁顺手些
    neoblackcap
        15
    neoblackcap  
       2020-05-11 17:35:08 +08:00
    @crella 解析 html ?你去看看 nginx 的不就结了。基本上都是拿 nginx 的代码改一下。要不然你去看 pichttpparser 也可以,不过那个到底有多标准,我不好说了。nginx 解析 html 的代码好像也就一个文件,非常短小精悍
    triangle111
        16
    triangle111  
       2020-05-12 11:58:06 +08:00
    有个开源的 Ruia,也是异步爬虫,就是插件没人开发。LZ 说的这些功能刚好都有
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   965 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 22:51 · PVG 06:51 · LAX 14:51 · JFK 17:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.