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
BBrother
V2EX  ›  Python

请教一个问题,怎么提高 python 爬虫的爬取效率?

  •  
  •   BBrother · 2016-08-25 09:45:33 +08:00 · 7654 次点击
    这是一个创建于 3022 天前的主题,其中的信息可能已经有所发展或是发生改变。

    写了个简单的协程爬虫爬取 B 站用户信息,代码如下:

    import requests
    import re
    import json 
    import datetime
    import asyncio
    
    def get_info(uid):
        url_info = "http://space.bilibili.com/ajax/member/GetInfo?mid=" #基本信息
        uid = str(uid)
        return loop.run_in_executor(None, requests.get, url_info+uid)
    
        
    async def user_info(num):
        for uid in range(num, num+10):
            info = await get_info(uid)
            info = json.loads(info.text)["data"]
            try:
            # print(datetime.datetime.fromtimestamp(info['regtime']))
                print("ok", uid)
                print(info)
            except UnicodeEncodeError as e:
                print("UnicodeEncodeError:", e)
            except TypeError:
                print(info)
                
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(asyncio.wait([user_info(x) for x in range(1, 1000, 10)]))
    except Exception as e:
        print("Error:", e)
    

    爬取 1000 条需要 50 秒左右,而且带宽占用也只有 220Kbps 左右的样子,有没有什么办法提高爬取的速度? B 站用户有 3800 万左右。

    谢谢指教。

    ps:1. 没机器做分布式 2. 我知道多进程,但我想问问协程能不能更有效率一点。

    30 条回复    2016-08-29 22:35:16 +08:00
    lbp0200
        1
    lbp0200  
       2016-08-25 09:59:49 +08:00
    多个爬虫+队列( redis )
    chy373180
        2
    chy373180  
       2016-08-25 10:05:30 +08:00 via iPhone
    协程与多进程并不冲突
    fatpa
        3
    fatpa  
       2016-08-25 10:19:20 +08:00
    消息队列啊少年
    abxialiang
        4
    abxialiang  
       2016-08-25 10:21:20 +08:00
    使用大量的代理 ip
    yangtukun1412
        5
    yangtukun1412  
       2016-08-25 10:21:55 +08:00
    使用 requests.Session 复用连接应该能稍微快一点.
    kinghui
        6
    kinghui  
       2016-08-25 10:29:07 +08:00
    使用异步非阻塞 I/O, 如 Tornado, Twisted 等框架
    BBrother
        7
    BBrother  
    OP
       2016-08-25 10:35:36 +08:00
    @chy373180 我知道不冲突,但是我想知道协程能不能再快点,很直觉得觉得协程的效率没发挥出来。
    BBrother
        8
    BBrother  
    OP
       2016-08-25 10:37:31 +08:00
    @fatpa 感觉没必要啊, B 站的 uid 是从 1 开始往上加的,直接切片就行了吧?
    BBrother
        9
    BBrother  
    OP
       2016-08-25 10:41:36 +08:00
    @kinghui 我觉得现在的代码已经异步非阻塞了啊?
    razrlele
        10
    razrlele  
       2016-08-25 10:41:58 +08:00 via iPhone
    看一下返回的 response status ,带宽没起来有可能是很多 request 直接被返回 403 了
    BBrother
        11
    BBrother  
    OP
       2016-08-25 10:42:31 +08:00
    @abxialiang 呃,这个,有什么意义吗?
    spider82
        12
    spider82  
       2016-08-25 10:42:41 +08:00
    可以看看 stackless ,我觉得瓶颈应该不在协程那里,单设备不用代理爬早晚被 BAN 。
    knightdf
        13
    knightdf  
       2016-08-25 10:49:33 +08:00
    我每次开 30 台机器爬,想要效率,只有一个途径,花钱
    BBrother
        14
    BBrother  
    OP
       2016-08-25 10:52:28 +08:00
    @knightdf 残酷的现实
    Mark3K
        15
    Mark3K  
       2016-08-25 10:57:54 +08:00
    代码使用了 coroutine ,但仍然是单线程在跑,没有利用到多核的优势,如果不考虑对方的反爬而只考虑效率的提高的话 可以再加上多进程试试
    erevus
        16
    erevus  
       2016-08-25 11:08:38 +08:00
    多进程+协程 能用到多核
    BBrother
        17
    BBrother  
    OP
       2016-08-25 12:34:42 +08:00
    哇啊,大家真热情,谢谢大家!拜谢!
    BBrother
        18
    BBrother  
    OP
       2016-08-25 12:35:18 +08:00
    @razrlele 看了下, status_code 都是 200
    BBrother
        19
    BBrother  
    OP
       2016-08-25 12:45:35 +08:00
    @spider82 嗯,看了下 stackless ,因为我要实现的功能比较简单,我觉得 python3.5.X 的 async/await 是够用的。现在只是试着跑跑啦,感觉差不多了就多进程+代理爬数据啦。
    kinghui
        20
    kinghui  
       2016-08-25 15:11:07 +08:00
    @BBrother https://docs.python.org/3/library/asyncio-eventloop.html#executor

    > Call a function in an Executor (pool of threads or pool of processes). By default, an event loop uses a thread pool executor (ThreadPoolExecutor).
    JhZ7z587cYROBgVQ
        21
    JhZ7z587cYROBgVQ  
       2016-08-25 15:33:16 +08:00
    为啥不用 aiohttp 要用 requests 呢?不会被阻塞住么?
    wmjie
        22
    wmjie  
       2016-08-25 17:48:26 +08:00   ❤️ 1
    requests 会被阻塞,换成 aiohttp 试试;
    https://github.com/aosabook/500lines/tree/master/crawler
    soulmine
        23
    soulmine  
       2016-08-25 18:18:48 +08:00
    不挂代理池+搞分布式然后多线程 你跑到下个月也跑不完
    pncltp
        24
    pncltp  
       2016-08-25 18:27:59 +08:00 via iPhone
    为什么要重新造轮子,用 scrapy 库呗。
    mutalisk
        25
    mutalisk  
       2016-08-26 08:03:22 +08:00 via iPhone   ❤️ 1
    requests+gevent
    hard2reg
        26
    hard2reg  
       2016-08-26 14:44:04 +08:00
    你好,我是 B 站的运维。我打算在后端加入反爬虫代码了!
    BBrother
        27
    BBrother  
    OP
       2016-08-26 15:48:01 +08:00
    @hard2reg 不!住手! 尔康.jpg
    Shliesce
        28
    Shliesce  
       2016-08-26 18:01:53 +08:00
    我是 B 站的研发,我要取消这个接口了。
    hard2reg
        29
    hard2reg  
       2016-08-26 20:32:10 +08:00
    @BBrother 笑尿
    BBrother
        30
    BBrother  
    OP
       2016-08-29 22:35:16 +08:00
    @Shliesce 你不会真是 B 站的吧?接口真没了啊。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1048 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 22:19 · PVG 06:19 · LAX 14:19 · JFK 17:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.