V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
Nick2VIPUser
V2EX  ›  程序员

(请教)如何提高爬虫的效率/采集速度

  •  1
     
  •   Nick2VIPUser ·
    nickliqian · 2018-01-04 11:55:55 +08:00 · 10978 次点击
    这是一个创建于 2549 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近做了一个爬虫任务,大概需要采集百万级的页面。 使用如下技术:

    python3
    requests
    xpath(解析)
    多线程(threading)
    代理 ip 池(95%有效,10 次 /1s 最多)
    redis(请求队列, 去重)
    mysql(储存)
    

    同时做好容错处理(重连)/反爬机制应对。 经过几次测试:控制

     [线程数量] 
     [进程数量] 
     [重连等待时间] 
     [报错等待时间] 
    

    得出一组每分钟采集最多数量的方案。 似乎遇到了瓶颈,此时不知道如何去优化采集速度。 没有想到的等会补充。。。 请教有经验的大神指点一下思路!谢谢各位了!!!

    第 1 条附言  ·  2018-01-04 14:42:31 +08:00
    回复太快被限制 1800s 了。
    珍惜附言机会,这里补充一下:

    1. 当前方案的问题主要来自
    采集速度并不理想,按照现行速度,使用一台云主机,带宽固定
    每天可能只有 6 ~ 8 万条左右,爬完几百万条可能需要 2~3 个月
    在不增加物理设备和额外带宽的前提下希望尽可能从技术 /代码上提高采集速度

    2. 目标站反爬措施敏感。在这块做好容错处理和延时,也会使程序耗费额外一定时间。
    经过使用不同的延时策略,发现延时过低也会使得采集速度变慢。

    3. 准备尝试一下使用异步网络请求模块,对比采集速度。
    51 条回复    2018-01-05 10:54:36 +08:00
    ilovebaicai
        1
    ilovebaicai  
       2018-01-04 11:59:04 +08:00   ❤️ 1
    Scrpy+redis 是一个选择。![scrapy-redis]( https://github.com/rmax/scrapy-redis)
    ilovebaicai
        2
    ilovebaicai  
       2018-01-04 12:00:06 +08:00   ❤️ 1
    抱歉,手抖,少打了个 a。
    wzwwzw
        3
    wzwwzw  
       2018-01-04 12:03:58 +08:00   ❤️ 1
    如果不用 scrapy 的话,就用
    - aiohttp
    - asyncio
    - aiosocks
    - Pool
    毕竟爬虫大部分时间都是在等待请求,所以异步应该会快很多。

    数量多的话还是推荐 scrapy ,分布式 scrapy-redis .
    exiaohao
        4
    exiaohao  
       2018-01-04 12:06:35 +08:00   ❤️ 1
    把采集任务丢给 celery 处理
    dhcn
        5
    dhcn  
       2018-01-04 12:41:29 +08:00   ❤️ 1
    pyspider,帮你完成包括人物分发在内的大多数技术基础设施工作
    so1n
        6
    so1n  
       2018-01-04 13:45:17 +08:00   ❤️ 1
    可以改用进程+协程
    zhchyu999
        7
    zhchyu999  
       2018-01-04 14:00:14 +08:00   ❤️ 1
    难道没人吐槽“代理 ip 池(95%有效,10 次 /1s 最多)”这个么
    BiggerLonger
        8
    BiggerLonger  
       2018-01-04 14:03:45 +08:00   ❤️ 1
    grequests
    harker
        9
    harker  
       2018-01-04 14:13:31 +08:00
    当前方案有问题么?百万级应该还能应付吧
    Nick2VIPUser
        10
    Nick2VIPUser  
    OP
       2018-01-04 14:17:18 +08:00
    @ilovebaicai
    @wzwwzw
    非常感谢,我尝试分别用 scrapy 和 async/await 做一下测试,然后再对比一下效率!
    qsnow6
        11
    qsnow6  
       2018-01-04 14:18:20 +08:00   ❤️ 1
    百万级应该没啥问题啊,大部分时间都是在网络耗时上面。
    不过,切换线程是有开销的,如果想进一步提升性能的话,建议用异步 or 协程。
    asuraa
        12
    asuraa  
       2018-01-04 14:19:12 +08:00   ❤️ 1
    百万级别重要的我觉得是

    1. 代理
    2. 断点续传
    3. 非阻塞多线程
    asuraa
        13
    asuraa  
       2018-01-04 14:19:53 +08:00   ❤️ 1
    Nick2VIPUser
        14
    Nick2VIPUser  
    OP
       2018-01-04 14:20:47 +08:00
    @exiaohao
    @so1n
    实际上我才使用十几个线程并发,cpu 资源远远够用,感觉可能是并发请求量或者是带宽的问题。
    Nick2VIPUser
        15
    Nick2VIPUser  
    OP
       2018-01-04 14:21:26 +08:00
    @dhcn
    这个框架没用使用过,会考虑了解一下特性以作比较!谢谢!
    Nick2VIPUser
        16
    Nick2VIPUser  
    OP
       2018-01-04 14:23:06 +08:00
    @BiggerLonger
    requests 换为 frequests 的话代码可能会变动比较大吧?刚刚只是粗略的看了一下 frequests 的 demo。
    Nick2VIPUser
        17
    Nick2VIPUser  
    OP
       2018-01-04 14:25:17 +08:00
    @qsnow6
    谢谢您,主要想提升采集速度,测试过 10/15/20 个线程的采集速度,结果发现 10 个线程的采集速度是最快的,非常困惑。这里每次请求都使用不同的经过测试的代理 IP,不知道是不是带宽限制导致。
    MontagePa
        18
    MontagePa  
       2018-01-04 14:25:43 +08:00   ❤️ 1
    celery 这个,然后你再多线程,考虑好去重就行。
    qsnow6
        19
    qsnow6  
       2018-01-04 14:28:05 +08:00   ❤️ 2
    @Nick2VIPUser 不是带宽限制,应该是切换线程的问题;

    多线程跑的话,一般情况下 10-12 左右是最快的,更增加更多的线程速度反而会下降。
    liupanhi
        20
    liupanhi  
       2018-01-04 14:29:23 +08:00   ❤️ 1
    @wzwwzw 长见识了,这么多好东西!
    NxnXgpuPSfsIT
        21
    NxnXgpuPSfsIT  
       2018-01-04 14:37:40 +08:00   ❤️ 1
    @Nick2VIPUser 可以试试 Trip, 替换 requests 比较方便,github.com/littlecodersh/trip
    急用的话可以直接 gevent 碰碰运气。
    qsnow6
        22
    qsnow6  
       2018-01-04 14:55:13 +08:00   ❤️ 1
    给个参考值,scrapy 单进程可以达到 7200 pages/min
    lhx2008
        23
    lhx2008  
       2018-01-04 15:02:50 +08:00 via Android   ❤️ 1
    每天 6-8 万就是每秒才爬 1 个,开了 10 个线程的话就是平均一个线程 10s 爬一条,这也太不理想了吧,每个线程 1s 爬一条,一天就 80 万了
    bazingaterry
        24
    bazingaterry  
       2018-01-04 15:06:43 +08:00   ❤️ 1
    上 scrapy,而且掏錢買代理池吧
    2ME
        25
    2ME  
       2018-01-04 15:07:31 +08:00   ❤️ 1
    你服务器如果不是小水管的话 你爬的是大文本吗? 大文本的话主要是 IO 影响效率 和线程关系并不大 还有你 1 条记录需要爬取几个页面 以及你的 IP 池质量如何 如果是 1 个页面并且爬取目标不是大文本,ip 池质量优异的话 这个速度可能慢了点 如果你为了对抗反爬虫 sleep 的时间比较久还是正常的
    Zzzzzzzzz
        26
    Zzzzzzzzz  
       2018-01-04 15:09:10 +08:00   ❤️ 1
    铺节点+队列+代理池, 问题是你得考虑下目标站能不能扛住你的 CC
    windfarer
        27
    windfarer  
       2018-01-04 15:10:35 +08:00   ❤️ 1
    百万级又不多,单机 scrapy 都够用了吧,主要代理要好
    Nick2VIPUser
        28
    Nick2VIPUser  
    OP
       2018-01-04 16:35:56 +08:00
    @zhchyu999
    这个为什么会被吐槽呀?公司有自己的代理池,但是数量较少;目标站点反爬策略比较敏感,所以使用付费的代理 IP 池,每次请求都会使用不同的 IP。
    Nick2VIPUser
        29
    Nick2VIPUser  
    OP
       2018-01-04 16:37:43 +08:00
    @qsnow6 不知道是不是线程一多了网络堵塞导致的采集速度过慢。
    Nick2VIPUser
        30
    Nick2VIPUser  
    OP
       2018-01-04 16:39:18 +08:00
    @luodaoyi
    代理 /断点续爬 /去重都做了,非阻塞的意思就是用协程或是异步?我去看看您发的链接 谢谢
    Nick2VIPUser
        31
    Nick2VIPUser  
    OP
       2018-01-04 16:58:54 +08:00
    @qsnow6
    @lhx2008
    @bazingaterry
    这个网站产生的详情页面的 url 和 cookie 有效期都很短,
    针对同一个 cookie 在短时间内高频率(大概是小于 1 次 /1s )的访问会立即失效
    大概是用来区分是否是机器人

    其实为什么每秒才爬一个,是因为对于 10 个线程每个线程都做了延时。每个线程获得一个新的 cookie 后每次请求都会间隔 3 秒,否则就会大量的报异常。这样的话,整体来说最优的情况每秒也只发出了 3 个请求,还没算上`去重入库解析异常处理`的时间。

    现在思路也比较清晰,就是提高并发量,尝试加了线程和进程,并没有效果。
    所以在研究把异步网络加上来。
    Nick2VIPUser
        32
    Nick2VIPUser  
    OP
       2018-01-04 17:14:34 +08:00
    @2ME 除了 sleep,还设置了 Connect time out 和 Read time out ( Proxy Connect time out 异常较少),同时也发现 Read time out 频繁发生,是否是从代理 ip 读取数据的时候超时,也就意味代理发送请求失败或者回传给本地失败?
    2ME
        33
    2ME  
       2018-01-04 17:44:33 +08:00   ❤️ 1
    @Nick2VIPUser 那就是你代理 ip 质量太差了 加钱数据可及 readtimeout 频繁 每天抓 6-8 万很正常了
    2ME
        34
    2ME  
       2018-01-04 17:48:00 +08:00   ❤️ 1
    @Nick2VIPUser 你 debug 一下基本就会发现绝大多数时间都浪费在超时了 即使是小水管都够呛能跑满带宽
    gouchaoer
        35
    gouchaoer  
       2018-01-04 17:54:08 +08:00   ❤️ 1
    第一代理 ip 不够
    gouchaoer
        36
    gouchaoer  
       2018-01-04 17:54:43 +08:00   ❤️ 1
    第一次看到爬虫自己是瓶颈的,大家都是怕爬坏了别人
    Nick2VIPUser
        37
    Nick2VIPUser  
    OP
       2018-01-04 18:07:54 +08:00
    @Zzzzzzzzz
    @windfarer
    目前还没有用 scrapy,并发太高,怕抓回来一堆异常。也在慢慢的加并发量,尽量不给网站造成太大压力。
    Nick2VIPUser
        38
    Nick2VIPUser  
    OP
       2018-01-04 18:09:32 +08:00
    @2ME 有道理,我增加额外的 ip 代理测试一下,感谢!
    Nick2VIPUser
        39
    Nick2VIPUser  
    OP
       2018-01-04 18:11:23 +08:00
    @gouchaoer 硬性条件没有提升起来呀,如果不考虑其他要花钱 /额外设备的条件,固定一台主机固定带宽,如果要增加速度还有什么办法?
    qsnow6
        40
    qsnow6  
       2018-01-04 18:35:42 +08:00 via iPhone
    加钱买多点代理就行了
    Nick2VIPUser
        41
    Nick2VIPUser  
    OP
       2018-01-04 19:03:42 +08:00 via iPhone
    @qsnow6 您是否了解质量好点的代理 ip,如果方便透露可以讲一下,目前付费购买的这家感觉质量还是提不上来...
    qsnow6
        42
    qsnow6  
       2018-01-04 19:10:18 +08:00   ❤️ 1
    WuMingyu
        43
    WuMingyu  
       2018-01-04 19:35:12 +08:00 via iPhone   ❤️ 1
    用协程的话可以试试这个 https://github.com/6ugman/ant_nest,速度比 scrapy 快?(不确定,没有精确测试)不过很可能有 bug😅
    anasplrt34
        44
    anasplrt34  
       2018-01-04 20:33:08 +08:00   ❤️ 1
    爬过十亿级数据的来吐个槽 要想速度快 加机器 加 IP 只有两条路 其他的比如什么优化什么异步多进程多协程线程都没什么作用 就比如一个网站限制单个 IP 一秒访问一次 你代码写出花来一秒也只能请求一次 这不是客户端也不算服务端 这是爬虫最大的问题 所以还是加钱吧
    Nick2VIPUser
        45
    Nick2VIPUser  
    OP
       2018-01-04 20:49:10 +08:00 via iPhone
    @qsnow6 谢谢🙏!!
    Nick2VIPUser
        46
    Nick2VIPUser  
    OP
       2018-01-04 20:50:43 +08:00 via iPhone
    @anasplrt34 您很幽默,说到点上了,我折腾了一天,现在才想清楚,不过收获很大,谢谢!!
    Nick2VIPUser
        47
    Nick2VIPUser  
    OP
       2018-01-04 20:51:46 +08:00 via iPhone
    @WuMingyu 好的,谢谢!今天一天收获了好多好东西😁
    easylee
        48
    easylee  
       2018-01-04 23:41:45 +08:00
    来学习了,Mark~
    anexplore
        49
    anexplore  
       2018-01-04 23:50:58 +08:00
    如果你每个线程都要休息 3s 的话,为啥要搞多线程呢?一个线程不就行了嘛,单线程异步 IO + 代理 IP 即可,根据带宽以及代理量控制并发,
    PythonAnswer
        50
    PythonAnswer  
       2018-01-05 00:41:45 +08:00 via Android
    协程 节约点资源。

    不过你的 ip 池质量不行,速度提高不了。
    goodryb
        51
    goodryb  
       2018-01-05 10:54:36 +08:00
    为啥不能增加物理资源,开个 10 台机器,效率不就提高 10 倍了,有时候真不要死脑经,先把事情解决了再说。

    按照你的说法,假设 1 台主机需要 3 个月( 90 天),提高 10 倍之后,就需要 9 天,一周多就搞完了。

    如果你今天在这里问了这么多,回去修改代码,换框架,验证,一周后搞出个新程序来,效率提高了 10 倍,那你需要的时间是 7+9 = 16 天

    所以呢,技术不够,机器来凑,云主机按量付费也没多少,如果你爬回来的数据连这点机器的钱都不值得,那我估计更不值得你投入这么大的人力去搞这个东西。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2965 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 11:12 · PVG 19:12 · LAX 03:12 · JFK 06:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.