大家好,又见面了,我是你们的朋友全栈君。
From:https://blog.csdn.net/bone_ace/article/details/50903178
微博爬虫单机每日千万级的数据 微博爬虫总结:https://blog.csdn.net/nghuyong/article/details/81251948
Python 爬虫——新浪微博(网页版):https://blog.csdn.net/qq_37267015/article/details/71512824
github 地址:https://github.com/LiuXingMing/SinaSpider
github 地址:https://github.com/CUHKSZ-TQL/WeiboSpider_SentimentAnalysis
微博访客 cookie 池
微博爬虫 — 自动获取访客 Cookie:https://cloud.tencent.com/developer/article/1615151
# -*- coding: utf-8 -*-
# @Author :
# @Date :
# @File : add_wb_cookie.py
# @description : XXX
import redis
import json
import random
import requests
import datetime
import multiprocessing
from urllib.parse import quote
from concurrent import futures
#############################################
REDIS_HOST_local = '127.0.0.1'
REDIS_PORT = 6379
REDIS_DB = 0
COOKIE_POOL = 'weibo:cookie'
#############################################
proxy_list = [
'http://127.0.0.1:8888',
'http://127.0.0.1:8888',
'http://127.0.0.1:8888',
]
class WBCookiePool(object):
def __init__(self):
self._redis_conn_pool_local = redis.ConnectionPool(
host=REDIS_HOST_local,
port=REDIS_PORT,
db=REDIS_DB
)
self.redis_conn_local = redis.StrictRedis(connection_pool=self._redis_conn_pool_local)
pass
def __del__(self):
pass
@staticmethod
def get_tid():
"""
获取 tid,c,w
:return:tid
"""
tid_url = "https://passport.weibo.com/visitor/genvisitor"
data = {
"cb": "gen_callback",
"fp": {
"os": "3",
"browser": "Chrome69,0,3497,100",
"fonts": "undefined",
"screenInfo": "1920*1080*24",
"plugins": "Portable Document Format::internal-pdf-viewer::Chrome PDF Plugin|::"
"mhjfbmdgcfjbbpaeojofohoefgiehjai::Chrome PDF Viewer|::internal-nacl-plugin::Native Client"
}
}
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
}
proxy_host = random.choice(proxy_list)
proxies = {
'http': proxy_host,
'https': proxy_host,
}
req = requests.post(
url=tid_url, data=data, headers=headers,
# proxies=proxies
)
if req.status_code == 200:
ret = eval(
req.text.replace("window.gen_callback && gen_callback(", "").replace(");", "").replace("true", "1"))
return ret.get('data').get('tid')
return None
def get_cookie(self):
"""
获取完整的 cookie
:return: cookie
"""
tid = self.get_tid()
if not tid:
return None
cookies = {
"tid": tid + "__095" # + tid_c_w[1]
}
url = f"https://passport.weibo.com/visitor/visitor?a=incarnate&t={quote(tid)}" \
f"&w=2&c=095&gc=&cb=cross_domain&from=weibo&_rand={random.random()}"
# print(url)
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
}
proxy_host = random.choice(proxy_list)
proxies = {
'http': proxy_host,
'https': proxy_host,
}
req = requests.get(
url, cookies=cookies, headers=headers,
# proxies=proxies
)
if req.status_code != 200:
return None
ret = eval(
req.text.replace("window.cross_domain && cross_domain(", "").replace(");", "").replace("null", "1"))
try:
sub = ret['data']['sub']
if sub == 1:
return None
subp = ret['data']['subp']
except KeyError:
return None
return sub, subp
def del_expire_cookie(self, max_time_int=None):
self.redis_conn_local.zremrangebyscore(COOKIE_POOL, min=0, max=max_time_int)
def add_cookie_2_redis(self):
count = 0
while True:
while True:
try:
sub, sub_p = self.get_cookie()
break
except BaseException as be:
print(be)
continue
count += 1
expire_time = datetime.datetime.now() - datetime.timedelta(minutes=10)
expire_time_int = int(expire_time.timestamp())
self.del_expire_cookie(max_time_int=expire_time_int)
headers = {'cookie': f'SUB={sub};SUBP={sub_p}'}
print(headers)
# self.redis_conn.lpush(self.cookie_pool, json.dumps(headers, ensure_ascii=False))
timestamp_int = int(datetime.datetime.now().timestamp())
data_string = json.dumps(headers, ensure_ascii=False)
self.redis_conn_local.zadd(COOKIE_POOL, timestamp_int, data_string, )
def main():
wb_cookie_pool = WBCookiePool()
cpu_count = multiprocessing.cpu_count()
pool = futures.ThreadPoolExecutor(max_workers=cpu_count)
for i in range(cpu_count):
pool.submit(wb_cookie_pool.add_cookie_2_redis)
if __name__ == '__main__':
main()
爬虫功能:
- 此项目和QQ空间爬虫类似,主要爬取新浪微博用户的个人信息、微博信息、粉丝和关注(详细见此)。
- 代码获取新浪微博Cookie进行登录,可通过多账号登录来防止新浪的反扒(用来登录的账号可从淘宝购买,一块钱七个)。
- 项目爬的是新浪微博wap站,结构简单,速度应该会比较快,而且反扒没那么强,缺点是信息量会稍微缺少一些(可见爬虫福利:如何爬wap站)。
- 爬虫抓取微博的速度可以达到 1300万/天 以上,具体要视网络情况,我使用的是校园网(广工大学城校区),普通的家庭网络可能才一半的速度,甚至都不到。
环境、架构:
开发语言:Python2.7
开发环境:64位Windows8系统,4G内存,i7-3612QM处理器。
数据库:MongoDB 3.2.0
(Python编辑器:Pycharm 5.0.4;MongoDB管理工具:MongoBooster 1.1.1)
- 主要使用 scrapy 爬虫框架。
- 下载中间件会从Cookie池和User-Agent池中随机抽取一个加入到spider中。
- start_requests 中根据用户ID启动四个Request,同时对个人信息、微博、关注和粉丝进行爬取。
- 将新爬下来的关注和粉丝ID加入到待爬队列(先去重)。
使用说明:
启动前配置:
- MongoDB安装好 能启动即可,不需要配置。
- Python需要安装好scrapy(64位的Python尽量使用64位的依赖模块)
- 另外用到的python模块还有:pymongo、json、base64、requests。
- 将你用来登录的微博账号和密码加入到 cookies.py 文件中,里面已经有两个账号作为格式参考了。
- 另外一些scrapy的设置(如间隔时间、日志级别、Request线程数等)可自行在setting里面调。
运行截图:
数据库说明:
SinaSpider主要爬取新浪微博的个人信息、微博数据、关注和粉丝。
数据库设置 Information、Tweets、Follows、Fans四张表,此处仅介绍前面两张表的字段。
Information 表:
_id:采用 “用户ID” 作为唯一标识。
Birthday:出生日期。
City:所在城市。
Gender:性别。
Marriage:婚姻状况。
NickName:微博昵称。
Num_Fans:粉丝数量。
Num_Follows:关注数量。
Num_Tweets:已发微博数量。
Province:所在省份。
Signature:个性签名。
URL:微博的个人首页。
Tweets 表:
_id:采用 “用户ID-微博ID” 的形式作为一条微博的唯一标识。
Co_oridinates:发微博时的定位坐标(经纬度),调用地图API可直接查看具体方位,可识别到在哪一栋楼。
Comment:微博被评论的数量。
Content:微博的内容。
ID:用户ID。
Like:微博被点赞的数量。
PubTime:微博发表时间。
Tools:发微博的工具(手机类型或者平台)
Transfer:微博被转发的数量。
转载请注明出处,谢谢!(原文链接:http://blog.csdn.net/bone_ace/article/details/50903178)
微博爬虫,单机每日千万级的数据 && 吐血整理的微博爬虫总结
前言
此前我发布了一篇博客微博爬虫,每日百万级数据,并且把代码开源在了Github上,然后就有很多人联系我,也有公众号转载了这篇文章。
不过对于微博爬虫,我还是心虚的,因为没有解决账号池的问题,所以每天百万级的数据,是有水分的。单单爬好友关系,这种简单数据可以达到百万级,如果爬关键词搜索的微博,或者一个人的全部微博,是达不到百万级数据这个量的。
不过既然已经埋了坑,就要填!所以自从写了那片文章以后,就一直想构建一个稳定的单机每日千万级的微博抓取系统。
值得庆祝的是,这个问题现在已经全面解决了!也对微博爬虫有了更深层次的认识!
微博站点分析
目前微博一共有三个站点,分别是
https://weibo.cn
https://m.weibo.com
https://weibo.com
可以看到这三个站点的复杂程度是逐渐提高的,很显然,如果能在最简单的weibo.cn完成的抓取,肯定不去复杂的weibo.com上去抓,但是事实上,有的只能在复杂的抓取!
那什么任务是weibo.cn完成不了的呢?可以说,抓取一个人的全部微博,抓取好友关系,抓取个人信息,这些都能在weibo.cn这个站点完成。
但是,就是有一个任务,weibo.cn实现不了,就是高级搜索
微博高级搜索
可能你经常有这样的需要,比如最近疫苗事件兴起,你要抓取7月10号到7月20号这段时间,提及到疫苗这个关键词的微博。
这其实是一个非常刚性的需求,这就要采用微博的高级搜索来完成了。
对于高级搜索接口,微博三个站点的情况是:
weibo.cn
高级搜索入口:https://weibo.cn/search/mblog?advanced=mblog&f=s
可以看到这里可以筛选的条件是,类型,用户,时间,注意,这里的时间是以天为单位。
下面具体搜索一个关键词,疫苗
可以看到一页有10条搜索的结果,最多显示100页,也就是1000条结果,
所以,一次搜索的结果,最多返回1000条微博,
而这个站点的时间单位是天,所以比如搜索的时间段是10天,那么最多能抓取到10*1000=10000条数据。
m.weibo.com
很遗憾这个站点没有高级搜索接口
weibo.com
高级搜索入口:https://s.weibo.com
可以看到这里可以筛选的条件是,类型,用户,时间,地区,注意,这里的时间是以小时为单位。
这个站点一页是20条微博,最多50页,所以一次搜索也是最多返回1000条微博数据
但是这个站点的时间单位是小时,
所以比如搜索的时间段是10天,那么最多能抓取到10*24*1000=240000条数据。
总结
- 对于搜索接口,只能选择weibo.com和weibo.cn
- weibo.com的筛选条件更加丰富,包括了地区,时间段更细,以小时为单位
- 所以如果希望抓取尽可能多的关键词搜索结果,需要采用weibo.com
所以仅仅高级搜索有可能需要用到weibo.com,并且是你需要的搜索结果数据很大,并且筛选条件很细,比如地区,其他所有爬虫需求都可以通过weibo.cn这个站点来抓取,包括比较粗略的高级搜索
微博抓取经验总结
-
微博不封IP,只封账号
微博不封IP,只封账号
微博不封IP,只封账号
重要的事,说三遍。这意味着,只需要购买大量账号,构建账号池即可,不需要构建IP池
ps 账号购买地址 http://www.xiaohao.shop/ 需要翻墙 -
微博登陆问题
weibo.cn 可能爬的人多了,出现了很恶心的滑块验证码
破解方案参考这里,滑动宫格验证码都给碰上了?没事儿,看完此文分分钟拿下!
wiebo.com 还是传统的验证码,5位数的数字字母组合
这种验证码可以通过扫码平台解决。具体的登陆代码参考这里
不过,由于你买的小号,可能由于频繁操作,被微博盯上了,登陆进去是账号异常,这就会产生非常恶心的验证码,如下图
这种情况,我建议你放弃治疗吧,不要想着破解这种验证码了,所以一般买的小号,不是100%可以用,有一部分是异常账号的!
构建千万级的爬虫系统
根据以上这些分析以后,要想构建千万级别的爬虫系统,只要做一件事情构建账号池。
构建账号池的步骤也非常简单:
1. 购买大量账号
2. 登陆进微博,保存下cookie
就这两步,以后每次请求,只要随机从账号池中选择一个账号即可。
对于weibo.cn和weibo.com这两个站点的cookie是不同的,所以要构建两个账号池,一个cn站点的,一个com站点的。
这时候,你结合我之前写的项目WeiboSpider就可以轻松达到每日百万级的数据抓取了!
注意这里实际的抓取速度和你的账号池大小和电脑的带宽有很大关系,如果账号池不大,请求的间隔延迟就需要时间长一点,如果带宽小的话,每次请求的耗时也会长一点
我的数据是,
账号池里230个账号,每次请求延迟为0.1秒,可以达到一天200~300万的抓取结果。
冲刺千万级
我一直认为,我上面构建的这个爬虫,已经占满了带宽!
有一次,我又启动了一个爬虫程序,发现另一个爬虫,也可以达到一天200~300万的抓取速度,同时之前的爬虫也是在以一天200~300万的抓取速度在运行,
所以,仅仅是因为CPU限制了爬虫的抓取量,而不是网络IO!
所以只需要用多进程优化即可,这里推荐Redis-Scrapy,所有的爬虫共享一个Redis队列,通过Redis统一给爬虫分配URL,这样就是一个分布式的抓取系统了。
可以分别部署在不同的机器上(如果一个机器带宽/CPU占用满了),或者就在一个机器上开多个进程即可。
就这样,我开了5个进程,不敢多开,毕竟账号池还是200多个。
然后结果就是:
一分钟可以抓取8000条数据,一天可以达到1100万+
这个抓取系统目前一直在稳定运行
所以就此实现了最初的目标,千万级别的微博爬虫系统
总结
- 解决微博登陆问题,并构建账号池
- 通过scrapy-redis框架构建分布式系统
- 深入分析微博高级搜索需求的解决方案,并编写weibo.cn和weibo.com两个站点的爬虫
至此,可以说,彻底解决了一切关于微博爬虫的问题!!!
开源代码在这里,你需要添加自己的账号池.
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/128843.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...