scrapy多cookies+ip代理稳定爬取微博m站评论以及子评论

为了以后的深度学习可以爬取更多更好的语料以及其他资源,先拿weibo移动端试了下手(果然一进就全是坑~)


具体scrapy可以联系我获取哦~

1、分析weibo登陆以获取cookies

1)预请求获取服务器信息

  • 请求的url
pre_url = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack" \
"&su=" + su + "&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.19)&_=" + str(int(time.time() * 1000))
  • 其中su是加密后的用户名 最后的是当前时间戳
  • su的加密方式如下
username_quote = quote_plus(self.username)
username_base64 = base64.b64encode(username_quote.encode("utf-8"))
return username_base64.decode("utf-8")
  • 得到服务器信息用于构建请求登陆的url

  • 具体的含义就不解释啦 需要的小伙伴可自行百度~

2)构建请求登陆url

self.form_data = {
            'entry': 'weibo',
            'gateway': '1',
            'from': '',
            'savestate': '7',
            'useticket': '1',
            'pagerefer': "https://passport.weibo.com",
            'vsnf': '1',
            'su': su,
            'service': 'miniblog',
            'servertime': server_time,
            'nonce': nonce,
            'pwencode': 'rsa2',
            'rsakv': rsakv,
            'sp': password_secret,
            'sr': '1366*768',
            'encoding': 'UTF-8',
            'prelt': '115',
            "cdult": "38",
            'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
            'returntype': 'TEXT'
        }
  • 其中密码加密
"""对密码进行 RSA 的加密"""
rsaPublickey = int(pubkey, 16)
key = rsa.PublicKey(rsaPublickey, 65537)  # 创建公钥
message = str(server_time) + '\t' + str(nonce) + '\n' + str(self.password)  # 拼接明文js加密文件中得到
message = message.encode("utf-8")
ps = rsa.encrypt(message, key)  # 加密
ps = binascii.b2a_hex(ps)  # 将加密信息转换为16进制
return ps
  • 登陆url
login_url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)&_'
login_url = login_url + str(time.time() * 1000)
  • 一般需要输入验证码 利用服务器数据pcid 请求并获取验证码
  • 请求验证码url
cha_url = "https://login.sina.com.cn/cgi/pin.php?r="
cha_url = cha_url + str(int(random.random() * 100000000)) + "&s=0&p=" + p_cid
  • 保存到本地并打开输出即可
  • 后期会使用神经网络进行验证码识别
    在这里插入图片描述

3)登陆跳转

  • 从登陆请求中得到的response
  • 提取ticket
'ticket': 'XXX'
  • 并从其中匹配出ssosavestate
save_pattern = r'==-(\d+)-'
ssosavestate = int(re.findall(save_pattern, ticket)[0]) + 3600 * 7
  • 构造params v1.4.18->v1.4.19
"callback": "sinaSSOController.callbackLoginStatus",
"ticket": ticket,
"ssosavestate": str(ssosavestate),
"client": "ssologin.js(v1.4.19)",
"_": str(time.time() * 1000),
  • 以及url和header
jump_url = "https://passport.weibo.com/wbsso/login"
jump_headers = {
        "Host": "passport.weibo.com",
        "Referer": "https://weibo.com/",
        "User-Agent": headers["User-Agent"]
     }
  • 再从respones获取uid 构造url
web_wb_url = "http://weibo.com/%s/profile?topnav=1&wvr=6&is_all=1" % uuid_res
  • 跳转m站请求
https://passport.weibo.cn/sso/crossdomain?service=sinawap&display=0&ssosavestate='ssosavestate'&url=https%3A%2F%2Fm.weibo.cn%2Fdetail%2F4513513248445166%3Fsudaref%3Dlogin.sina.com.cn&display=0&ticket='ticket'&retcode=0
  • 登陆已经成功 下一步跳转m站
m_Params = {
        "url": "https://m.weibo.cn/",
        "_rand": _rand,
        "gateway": "1",
        "service": "sinawap",
        "entry": "sinawap",
        "useticket": "1",
        "returntype": "META",
        "sudaref": "",
        "_client_version": "0.6.26",
     }
m_url = "https://login.sina.com.cn/sso/login.php"
  • 保存cookies 使用了LWPCookieJar
self.session.cookies = ck.LWPCookieJar(filename=self.cookies_path)
# 保存
self.session.cookies.save()
  • 扫描cookies文件
for file in os.listdir(cookie_files):
    if file.endswith('.txt'):
        cookies_temp = ck.LWPCookieJar(cookie_files + "/" + file)
        cookies_temp.load(ignore_discard=True, ignore_expires=True)
        self.cookie_dict.append(requests.utils.dict_from_cookiejar(cookies_temp))
  • 在中间件随机或者顺抽取一个即可 因为访问需要带上cookies哦~

通过此次爬虫测试 发现m站对ip地址ban得不狠 但还是不能太频繁 否则也会被“求着歇歇” 反而是对账号比较敏感 账号可以说是越多越好 三个感觉已经足够 但文明爬虫 请求的频率还是得慢点~

2、m站请求隐藏细节

1)分析请求

  • ajax加载方式
  • 首页评论加载的请求 是固定的 只有id和mid不同 都是博客id
https://m.weibo.cn/comments/hotflow?id=4513513248445166&mid=4513513248445166&max_id_type=0
  • 下一页的请求
https://m.weibo.cn/comments/hotflow?id=4513513248445166&mid=4513513248445166&max_id=216909405545407&max_id_type=0
  • 不同之处

  • 1、多了max_id

  • 2、max_id_type的值也不固定为0

  • 那么该去哪里找max_id和max_id_type

  • 再看response

  • 当前页面的max_id和max_id_type可以在上一页的response中找到
    在这里插入图片描述

  • 如此一来 就可以愉快的进行爬取啦~

  • 子评论

  • 子评论首页请求

https://m.weibo.cn/comments/hotFlowChild?cid=4513525815570069&max_id=0&max_id_type=0
  • cid:父评论的id

  • max_id:与父评论max_id一致

  • max_id_type:与父评论max_id_type一致

  • 子评论其他页请求

https://m.weibo.cn/comments/hotFlowChild?cid=4513525815570069&max_id=4513615728599918&max_id_type=0
  • 与父级评论一致 只需要确保cid唯一即可

  • 注意事项

  • 1、首页评论请求可以无限次访问

  • 2、其他页请求只能访问两次 再多就会返回{‘ok’:‘0’}

  • 3、严格按照顺序访问

  • 4、并且max_id是递减的 个人觉得其生成方式是按照先后顺序的 就是对于某一页评论 不是单纯的当前博客评论页 而是所有的博客的评论页生成的先后顺序

  • 5、max_id_type目前值见到0/1 并且当max_id_type为0时 max_id长度比较长 当max_id_type为1时 max_id长度比较短 猜测是两个不同的生成原理

  • 6、最后一页判断 max_id会再次返回来0

3、scrapy开启爬取

话不多说 上代码~

  • 下载中间件
DOWNLOADER_MIDDLEWARES = {
    'mWeiBo.middlewares.MweiboDownloaderMiddleware': 543,
    'mWeiBo.middlewares.UserAgentDownloaderMiddleware': 300,
    'mWeiBo.middlewares.CookiesDownloaderMiddleware': 200,
    'mWeiBo.middlewares.IpProxyDownloaderMiddleware': 100,
}
  • spider主逻辑
class MweiboSpider(scrapy.Spider):
    name = 'mweibo'
    allowed_domains = ['m.weibo.cn']

    # 初始化
    def __init__(self):
        super(MweiboSpider, self).__init__()
        self.count = 0
        # 博客id
        self.wb_id = '4513496224687345'
        self.url = 'https://m.weibo.cn/comments/hotflow?id=' + self.wb_id + '&mid=' + self.wb_id + '&max_id_type=0'

        # 加载cookie
        cookies_path = "/Users/sugarmei/mWeiBo/mWeiBo/spiders/cookies_files/cookies2.txt"
        cookies = ck.LWPCookieJar(cookies_path)
        cookies.load(ignore_discard=True, ignore_expires=True)
        # 将cookie转换成字典
        self.cookie_dict = requests.utils.dict_from_cookiejar(cookies)

    def start_requests(self):
        # 开始发布请求任务
        yield scrapy.Request(url=self.url, cookies=self.cookie_dict, callback=self.parse, errback=self.error)

    def parse(self, response):
        # 当前ip被ban 继续ip代理请求
        if response.status == 403:
            yield scrapy.Request(url=response.url, cookies=self.cookie_dict, callback=self.parse, dont_filter=True)

        # 发生异常
        data = json.loads(response.text)
        if data['ok'] == 0:
            time.sleep(2)
            print("请求数据为空 重新发出请求")
            yield scrapy.Request(url=response.url, cookies=self.cookie_dict, callback=self.parse, dont_filter=True)

        else:
            # 拼接url
            max_id = data['data']['max_id']
            max_id_type = data['data']['max_id_type']
            if data['data']['max_id'] == 0:
                print("此次评论爬取结束!")
                return
            url_max = 'https://m.weibo.cn/comments/hotflow?id=' + self.wb_id + '&mid=' + self.wb_id + '&max_id=' + str(
                max_id) + '&max_id_type=' + str(
                max_id_type)
            # 拿到其中的text
            for comment in data['data']['data']:
                # 数据持久化
                item = MweiboItem()
                item['username'] = comment['text']
                item['comment'] = comment['user']['screen_name']
                self.count += 1
                yield item
            print("当前获取了共 " + str(self.count) + " 条评论")
            yield scrapy.Request(url=url_max, cookies=self.cookie_dict, callback=self.parse, dont_filter=False)

  • 爬虫结果

  • 大学升作弊被捉坠亡学校应该担责吗
  • 没有爬取子评论
    在这里插入图片描述
  • 加上爬取子评论的功能
  • 需要判断是否有恢复 more_info_type不为0即可
    在这里插入图片描述
  • 加上子评论代码
# more_info_type为0的评论没有回复
if comment['more_info_type'] != 0:
  		print('该评论有人回复', "回复数量:", comment['total_number'])
  		# 每次的cid都不一样 但是需要获取子评论 都要从
  		cid = comment['rootid']
  		# 在循环里面发出爬取该评论回复的请求max_id=0&max_id_type=0参数开始
  		url_sub = "https://m.weibo.cn/comments/hotFlowChild?cid=" + cid + "&max_id=0&max_id_type=0"
  		yield scrapy.Request(url=url_sub, cookies=self.cookie_dict, callback=self.parse_sub,
                                         dont_filter=False)
# 处理子评论
def parse_sub(self, response):
    # 有些评论是没有回复的 需要做判断
    data = json.loads(response.text)
    if data['ok'] == 0:
        yield scrapy.Request(url=response.url, cookies=self.cookie_dict, callback=self.parse_sub, dont_filter=True)
    else:
        # 与之前一致 先找到max_id和max_id_type
        max_id = data['max_id']
        max_id_type = data['max_id_type']
        cid = data['rootComment'][0]['id']
        # 结束条件
        if max_id == 0:
            print(str(cid) + ":子评论爬取结束!")
            return
        # 否则
        url_max_sub = "https://m.weibo.cn/comments/hotFlowChild?cid=" + str(cid) + "&max_id=" + str(
            max_id) + "&max_id_type=" + str(max_id_type)
        for sub_comment in data['data']:
            # 数据库持久化
            # 数据持久化
            item = MweiboItem()
            item['rootid'] = str(cid)
            item['refid'] = '0'
            item['comment'] = sub_comment['text']
            item['username'] = sub_comment['user']['screen_name']
            self.sub_count += 1
            yield item
        yield scrapy.Request(url=url_max_sub, cookies=self.cookie_dict, callback=self.parse_sub, dont_filter=True)

  • 有其他想法的朋友可以一起交流哦 需要完整代码的也可以联系我
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值