写了个简单的协程爬虫爬取 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. 我知道多进程,但我想问问协程能不能更有效率一点。
![]() | 1 lbp0200 2016-08-25 09:59:49 +08:00 多个爬虫+队列( redis ) |
![]() | 2 chy373180 2016-08-25 10:05:30 +08:00 via iPhone 协程与多进程并不冲突 |
![]() | 3 fatpa 2016-08-25 10:19:20 +08:00 消息队列啊少年 |
4 abxialiang 2016-08-25 10:21:20 +08:00 使用大量的代理 ip |
5 yangtukun1412 2016-08-25 10:21:55 +08:00 使用 requests.Session 复用连接应该能稍微快一点. |
![]() | 6 kinghui 2016-08-25 10:29:07 +08:00 使用异步非阻塞 I/O, 如 Tornado, Twisted 等框架 |
![]() | 10 razrlele 2016-08-25 10:41:58 +08:00 via iPhone 看一下返回的 response status ,带宽没起来有可能是很多 request 直接被返回 403 了 |
![]() | 11 BBrother OP @abxialiang 呃,这个,有什么意义吗? |
12 spider82 2016-08-25 10:42:41 +08:00 可以看看 stackless ,我觉得瓶颈应该不在协程那里,单设备不用代理爬早晚被 BAN 。 |
![]() | 13 knightdf 2016-08-25 10:49:33 +08:00 我每次开 30 台机器爬,想要效率,只有一个途径,花钱 |
15 Mark3K 2016-08-25 10:57:54 +08:00 代码使用了 coroutine ,但仍然是单线程在跑,没有利用到多核的优势,如果不考虑对方的反爬而只考虑效率的提高的话 可以再加上多进程试试 |
![]() | 16 erevus 2016-08-25 11:08:38 +08:00 多进程+协程 能用到多核 |
![]() | 17 BBrother OP 哇啊,大家真热情,谢谢大家!拜谢! |
![]() | 19 BBrother OP @spider82 嗯,看了下 stackless ,因为我要实现的功能比较简单,我觉得 python3.5.X 的 async/await 是够用的。现在只是试着跑跑啦,感觉差不多了就多进程+代理爬数据啦。 |
![]() | 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). |
21 JhZ7z587cYROBgVQ 2016-08-25 15:33:16 +08:00 为啥不用 aiohttp 要用 requests 呢?不会被阻塞住么? |
22 wmjie 2016-08-25 17:48:26 +08:00 ![]() requests 会被阻塞,换成 aiohttp 试试; https://github.com/aosabook/500lines/tree/master/crawler |
![]() | 23 soulmine 2016-08-25 18:18:48 +08:00 不挂代理池+搞分布式然后多线程 你跑到下个月也跑不完 |
![]() | 24 pncltp 2016-08-25 18:27:59 +08:00 via iPhone 为什么要重新造轮子,用 scrapy 库呗。 |
25 mutalisk 2016-08-26 08:03:22 +08:00 via iPhone ![]() requests+gevent |
26 hard2reg 2016-08-26 14:44:04 +08:00 你好,我是 B 站的运维。我打算在后端加入反爬虫代码了! |
28 Shliesce 2016-08-26 18:01:53 +08:00 我是 B 站的研发,我要取消这个接口了。 |