毕设模块之一:最新版 微博网络爬虫(可登录版)

                                                 前言以及微博站点简单说明

论文查重和格式检测完成后,就继续做毕业设计。不过微博爬虫真的各种问题调试了一个月,先从破解登录,分析weibo.com和weibo.cn,发现weibo.com的难度太大,设计很多加密以及时间戳....但是weibo.com上面的信息真的很人性化,不论是布局还是美观度,或则我们想要的数据,都是呈现的很清晰明了,反观weibo.cn全是文字,布局混乱。weibo.cn是以前2g,3g时代用的老版本,在以前时代没有视频那些,基本都是文字为主,图片也比较少。下面放两张图片对比两个站点。 

                

                                     weibo.cn                                                                                                    weibo.com

 

我一开始就想用weibo.com,用浏览器F12和抓包工具charles,尝试了一段时间,最后放弃了。如果你真的非常想用weibo.com,这里我推荐一个b站up主破解weibo.com的视频供大家参考,请点击:传送门但是主流我看了博客大多数weibo爬虫都是用的主流的weibo.cn,可能大家都觉得weibo.com处理太头疼了,对于博主我来说亦是如此。

小本本记下来:虽然weibo.cn简陋了一些,但随之的好处就是登陆难度没有那么大(尽管没那么大,但是要处理的问题还是很多的)比如数据想用xpath或者json提取,统统都别想,看了以前的文章,好多都在用xpath,json解析数据,我这里尝试的时候,发现不管用哪个,解析的返回数据都为空!最终发现只有把返回的数据转成文本text,才能有数据,所以博主这里采用的scrapy框架+正则提取文本的方式。顺便再说下,如果你想用request网页级提取信息,也很难,博主这里尝试了的,scrapy和requests,同样的hearder,请求的接口,同样的表单数据,requests是会报错的,微博不会返回数据给你!这里博主简单分析了一下,是因为在进入weibo.cn域名的时候,会在登陆之前有脚本请求,如果你去分析会发现有个pre_login请求藏在js代码里面的,所以如果你很想用requests还得去分析...所以这里采用scrapy 的原因就是scrapy,在我们请求之前好像默认做了一些浏览器事情。

说明:因为我写的程序还没完成,还在进行中,所以只会公布出目前能够登陆的源码和简单的文章信息提取(未处理数据库部分),注意:因为微博这个平台数据时动态加载的,同时每个新闻信息太长的话,只会显示一部分,如果需要爬取全部内容需要其提取文章全文的地址,再次请求,才能得到文章全部的信息,下面是展示的动态GIF效果图。

 

 

不过还是得老生常谈,scrapy常用命令熟悉一下~

还是走个流程吧~

 一:开始一个爬虫项目:scrapy startproject +项目名

 eg:scrapy startproject weibo_info

 会自动生成目录如下:

 

 

二:创建spider爬虫

1.创建项目成功需要先切换目录到weibo_info     

     eg:cd weibo_info

2.创建微博爬虫    scrapy genspider +爬虫名 +爬取域名

eg:scrapy genspider weibo weibo.cn 创建完成后,spider目录下自动生成weibo的spider

 

三:在setting里面把遵守爬虫协议改为不遵守

ROBOTSTXT_OBEY = True 改为-> ROBOTSTXT_OBEY = False,用时设置下载延迟为1秒

 

取消DEFAULT_REQUEST_HEADERS 注释,加入自己的浏览器user-agent等信息伪装浏览器。着里面的信息可以去weibo.cn登录的时候可以用F12或者抓包工具,看请求头,然后把对应信息搬过来即可。

登录的请求头信息,需要去weibo.cn点击登录后,在点击登录按钮,会有个login请求文件,点开它就能看到请求头和参数,我们就把请求头信息拿下来,复制到setting里面的headers里面。

 

四:打开items.py文件,定义item容器,方便数据的存储,以及数据库的信息的储存。

代码如下:


class WeiboInfoItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    text_url=scrapy.Field()#新闻url地址
    text_publisher = scrapy.Field()#新闻作者
    text_start_time=scrapy.Field()#新闻发表时间
    text_title=scrapy.Field()#新闻标题
    text_content=scrapy.Field()#新闻内容
    text_like = scrapy.Field()  # 新闻点赞数
    text_transfers=scrapy.Field()#新闻转发量
    text_comments_numbers=scrapy.Field()#新闻评论数


class WeiboInfo_hot_commentsItem(scrapy.Item):
    hot_comment=scrapy.Field()#热点评论
    hot_like=scrapy.Field()#点赞数

五:把微博中的spider编写完成,在spider目录下找到weibo.py文件,编写 爬取逻辑代码

提取方法是正则提取,为什么不用xpath和json那么好用,不用呢?原因前面说了, 这两种方法得到结果是没有数据的,需要转换成text类型才可以,而文本类型用正则提取是很快很方便的。

这里附上正学习正则的网址,菜鸟教程:点击进入正则提取教程 。文章不长可以简单看下了解正则的常用提取方法。

 

下面应该是本文中的精华~

对于最后面代码部分解释和剖析:

def  start_requests(self)是scrapy的一个类的实例,是在爬虫开始之前做的工作,在提取信息之前,我们需要先登录账号的和密码的。

在weibo.cn中我们点击登录后(我这里先把密码输入错误),你在浏览器F12中或者在抓包工具中,可以在all或者xhr中发现login的ajax请求,会向服务器发送表单数据,里面包含我们的账号和密码,如果输入错误就不会显示账号,而输入正确,则会在很短时间内跳转,你有可能看不到这个请求了,这时候就需要抓包或者用其他方法把这个正确登录的login停住,我们就能更好的观察,不过我这里输入错误,就是不让跳转,方便看请求的url,表单数据,参数等。

这里我们总结出:

  1. 登录的url https://passport.weibo.cn/sso/login
  2. 需要提交表单数据
    
                'username': 'xxx',#你的账号
                'password': 'xxx',#你的密码
                'savestate': '1',
                'r': 'https://weibo.cn/',
                'ec': '0',
                'pagerefer': 'https://weibo.cn/pub/',
                'entry': 'mweibo',
                'wentry': '',
                'loginfrom': '',
                'client_id': '',
                'code': '',
                'qq': '',
                'mainpageflag': '1',
                'hff': '',
                'hfp': '',
            
  3. 请求登录用的是post请求不是get,所以要用scrapy中Request(),同时把表达数据传入进去。
  4. 登录成功会返回json数据,里面有20000000,就代表登录成功,反之登录失败

对于上面的代码代码还需要注意的事项

  1. 所有爬取的数据只有经过登录后才能运行
  2. 爬取的信息是自己登录账号关注的人发表的信息,比如博主用的这个小号,关注了中国日报,人民日报等等
  3. 数据库等后续功能,有需要的请自己完善,也可以参考博主专栏里面的爬虫专栏,里面有scrapy爬取数据后存mysql数据的例子
  4. 爬取的时候一定要限速,至少一秒,在setting里面或者在循环里面用time.sleep(),友情提示:请重新注册一个小号,避免大号被封
  5. 因为目前博主根据自己的需求也还在修改,所以目前代码可能还有很多问题,如果遇到了其他问题,可能博主也没法解决,请大家先自己解决,我这里就是提供基本的思路和基本代码,保证基本的数据提取。
  6. 如果大家有问题,欢迎留言,我看到后,会尽量帮助大家,如果有知道的大佬,欢迎提供解决方案,不胜感激。

代码如下:

这里要特别说明weibo.py注释的代码,是因为我自己需求变动或者实现起来困难较多,暂时还没完善,有需要完善的小伙伴自己拿到源码,可以修改。

# -*- coding: utf-8 -*-
import scrapy,json
from ..items import *
import time,re


class WeiboSpider(scrapy.Spider):
    name = 'weibo'
    allowed_domains = ['weibo.cn','weibo.com']
    start_urls = ['https://weibo.cn']

    #登录   在爬取信息之前先登录
    def start_requests(self):
        login_url="https://passport.weibo.cn/sso/login"
        fromdata={
            'username': 'xxxx', #你的账号
            'password': 'xxx', #你的密码
            'savestate': '1',
            'r': 'https://weibo.cn/',
            'ec': '0',
            'pagerefer': 'https://weibo.cn/pub/',
            'entry': 'mweibo',
            'wentry': '',
            'loginfrom': '',
            'client_id': '',
            'code': '',
            'qq': '',
            'mainpageflag': '1',
            'hff': '',
            'hfp': '',
        }
        yield scrapy.FormRequest(url=login_url,formdata=fromdata,callback=self.parse_login)

    def parse_login(self,response):
        #判断是否成功登录微博
        json_res=json.loads(response.text)
        if json_res['retcode']==20000000:
            info_url="https://weibo.cn/"
            yield  scrapy.Request(url=info_url,callback=self.parse_info)
        else:
            print("*"*100+'\n'+"登录失败")



    def parse_info(self, response):
        item= WeiboInfoItem() #导入item容器
        #每一篇文章对应的评论 文章是在数据库是自增的id从1开始,标记初始也为1
        text_comment_flag=1
        print("+"*100)
        # print(response.text)
        # 要转换成tex文本格式,因为微博用的动态加载数据,用xpath的话,数据提取不到
        res=response.text
        # print(res)
        weibo_info=re.findall(r'<div class="c" id=".*?">(.*?)<div class="s">',res)
        for info in weibo_info:
            # print(info)
            try:
                #因为文章太多了,随时又在更新新文章,非热门文章就过滤一下
                text_like= re.findall(r'<a href=.*?add.*?>赞\[(.*?)\]</a>', info)[0]
                text_comments_numbers= re.findall(r'<a href=.*?comment.*?>评论\[(.*?)\]</a>', info)[0]
                #过滤规则  点赞少于2000,或者评论少于200就pass掉
                # if int(text_like)<2000 or int(text_comments_numbers)<200:
                #     continue

                item['text_url']=re.findall(r'<span class="ctt">.*?<a href="(.*?)".*?',info)[0]#正则提取文章地址
                item['text_publisher']=re.findall(r'<a class="nk" href=.*?>(.*?)</a>',info)[0]
                text_start_time=re.findall(r'<span class="ct">(.*?)&nbsp',info)[0]
                # item['text_start_time']=
                item['text_title']=re.findall(r'【.*?>(.*?)</a>',info)[0]
                item['text_content']=re.findall(r'】(.*?)</span>',info)[0]
                ###新闻内容显示不全,源出处提取全部新闻内容
                # text_content=re.findall(r'】(.*?)</span>',info)[0]
                # if '>全文<' in text_content:
                #     #提取新闻全文网址
                #     detaile_content_url=re.findall(r"<a href='(.*?)'>全文</a>",text_content)[0]
                #     #再次请求全文网址
                #     print("全文地址:"+self.start_urls[0]+detaile_content_url)
                #
                #     yield scrapy.Request(url=self.start_urls[0]+detaile_content_url,callback=self.parse_detaile_content)

                    #过滤文章内容较短的
                    # if len(detaile_content['text_content'])<200:
                    #     continue
                    # item['text_content'] = detaile_content
                    # print("@"*100)
                    # print(detaile_content)
                # else:
                #                 #     print("else "*50)
                #                 #     item['text_content'] = text_content
                item['text_like']=text_like
                item['text_transfers']=re.findall(r'<a href=.*?repost.*?>转发\[(.*?)\]</a>',info)[0]
                item['text_comments_numbers']=text_comments_numbers


                print("文章地址:"+item['text_url'])
                print("文章发表人:"+item['text_publisher'])
                print("文章时间:"+text_start_time)
                print("文章标题:"+item['text_title'])
                print("文章内容:"+item['text_content'])
                print("文章点赞:"+item['text_like'])
                print("文章转发:"+item['text_transfers'])
                print("文章评论:"+item['text_comments_numbers'])
                print("文章内容长度"+str(len(item['text_content'])))


                #**********提取评论*********#
                # comments_url=re.findall(r'转发\[.*?\]</a>&nbsp;<a href="(.*?)" class="cc">评论.*?</a>',info)[0]
                # print("文章评论url:"+comments_url)
                # yield scrapy.Request(url=comments_url,meta={'flag':text_comment_flag},callback=self.parse_comments)
                # text_comment_flag+=1
                # # 分割线用来分割每个新闻
                print("*" * 100)
            except:
                continue

        # 提取下一页新闻地址
        try:
            next_url=re.findall(r'<form action="/\?.*?<a href="(.*?)">下页</a>',res)[0].replace("amp;","")
            print("=" * 100)
        except:
            next_url=None
        # 如果地址存在就拼接域名,再次请求,回调自身再次提取
        if next_url:
            print(self.start_urls[0]+next_url)
            yield scrapy.Request(url=self.start_urls[0]+next_url,callback=self.parse_info)

    #提取评论
    def parse_comments(self,response):
        item=WeiboInfo_hot_commentsItem()#导入热点评论容器
        print("6"*100)
        flag=response.meta['flag']
        print("flag:"+str(flag))
        res=response.text
        print(res)
        # hot_comments=re.findall(r'<span class="ctt">(.*?)</span>',res)
        # print(hot_comments)


 

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落凡尘.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值