Scrapy爬取新浪微博移动版用户首页第一条微博

释放双眼,带上耳机,听听看~!

大家好,本月第一次更新。

最近找了一份关于爬虫的实习工作,需要爬取较大量的数据,这时就发现通过自己编写函数来实现爬虫效率太慢了;于是又转回来用scrapy,以前稍微学习了一下,这次刚好爬爬微博练练手,而后再使用部分数据生成词云。

本次爬取的是新浪微博移动端(https://m.weibo.cn/),爬取的数据是用户微博首页的第一条微博(如下图),包括文字内容、转发量、评论数、点赞数和发布时间,还有用户名和其所在地区(后面可以分析不同地区微博用户的关心的热点话题)。

Scrapy爬取新浪微博移动版用户首页第一条微博

 

一、分析网页

 

  • 获取用户微博入口url

浏览发现使用的是使用Ajax渲染的网页,微博数据(https://m.weibo.cn/api/container/getIndex?containerid=102803_ctg1_5088_-_ctg1_5088&openApp=0&since_id=1)存储在json格式网页中,所以思路是先通过微博数据得到用户url(如下图),再来爬取后续内容。

Scrapy爬取新浪微博移动版用户首页第一条微博

  •  获取第一条微博数据

也是使用了Ajax渲染的网页,跟上面一样找到网页入口就行了。请求网址如下:

Scrapy爬取新浪微博移动版用户首页第一条微博

这样看网址的话毫无规律可言,简化后发现 https://m.weibo.cn/api/container/getIndex?containerid=1076032554757470就可以进入。而且containerid=107603(***)这里,括号里的数字刚好是用户的id号,因此我们可以通过这个来构造网页。

  • 获取用户所在地区

用户所在地在其基本资料中,如下图

Scrapy爬取新浪微博移动版用户首页第一条微博

地址为:Scrapy爬取新浪微博移动版用户首页第一条微博

同样进行简化得到:https://m.weibo.cn/api/container/getIndex?containerid=230283(***)_-_INFO其中括号里面是用户id号。

通过以上分析可知,获取用户的 id 号是本次爬取数据的关键,只需要用 id 构成网址,后面的爬取就相对简单了。下面是编程部分。

 

二、编程爬取

 注:转载代码请标明出处

 

  • 首先通过命令行创建 scrapy 爬虫。
scrapy startproject sinaweibo

scrapy genspider xxx(爬虫名) xxx(所在域名)
  • items.py定义爬虫字段
import scrapy


class SinaweiboItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = scrapy.Field()       #用户名
    first_news = scrapy.Field()     #首条微博
    dates = scrapy.Field()     #发布时间 
    zhuanzai = scrapy.Field()       #转载数
    comment = scrapy.Field()        #评论数
    agree = scrapy.Field()      #点赞数
    city = scrapy.Field()       #所在地区
  • 编写爬取代码
 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 from sinaweibo.items import SinaweiboItem
 4 import json
 5 import re
 6 import copy
 7 
 8 
 9 class WeibodiyuSpider(scrapy.Spider):
10     name = \'weibodiyu\'  #爬虫名
11     allowed_domains = [\'m.weibo.cn\']    #只在该域名内爬取
12     start_urls = [\'https://m.weibo.cn/api/container/getIndex?containerid=102803_ctg1_4188_-_ctg1_4188&openApp=0&since_id=1\'
13                   ]
14 
15     def parse1(self, response):
16         infos = json.loads(response.body)   #将内容转为json对象
17         item = response.meta[\'item\']    #利用meta方法传入item
18         city = response.meta[\'city\']    #传入城市
19         try:
20             name = infos[\"data\"][\"cards\"][0][\"mblog\"][\"user\"][\"screen_name\"]    #爬取名字
21             first_news = re.findall(\'([\\u4e00-\\u9fa5]+)\', str(infos[\"data\"][\"cards\"][0][\"mblog\"][\"text\"]), re.S)    #爬取微博内容,使用正则去除一些杂项如网页代码
22             dates = infos[\"data\"][\"cards\"][0][\"mblog\"][\"created_at\"]    #发布时间
23             zhuanzai = infos[\"data\"][\"cards\"][0][\"mblog\"][\"reposts_count\"]    #转载数
24             comment = infos[\"data\"][\"cards\"][0][\"mblog\"][\"comments_count\"]    #评论数
25             agree = infos[\"data\"][\"cards\"][0][\"mblog\"][\"attitudes_count\"]    #点赞数
26             #将数据赋给item
27             item[\'name\'] = name
28             item[\'first_news\'] = first_news
29             item[\'dates\'] = dates
30             item[\'zhuanzai\'] = zhuanzai
31             item[\'comment\'] = comment
32             item[\'agree\'] = agree
33             item[\'city\'] = city
34             return item    #返回
35         except IndexError or KeyError:
36             pass
37 
38     def parse2(self, response):    #获取所在地区函数
39         infos = json.loads(response.body)
40         try:
41             item = response.meta[\'item\']    #传入item
42             city_cont = str(infos[\"data\"][\"cards\"][1][\"card_group\"])
43             city = re.findall(\'card_type.*?所在地.*?item.*?:(.*?)}]\', city_cont, re.S)[0].replace(\'\\\'\', \'\').replace(
44                 \' \', \'\')    #城市
45             item[\'city\'] = city
46             ids = response.meta[\'ids\']    #传入id并赋给ids变量
47             n_url1 = \'https://m.weibo.cn/api/container/getIndex?&containerid=107603\' + ids
48             yield scrapy.Request(n_url1, meta={\'item\': item, \'city\': copy.deepcopy(city)}, callback=self.parse1)    #执行完上述命令后的步骤
49         except IndexError or KeyError:
50             pass
51 
52     def parse(self, response):
53         datas = json.loads(response.body)
54         item = SinaweiboItem()
55         for i in range(0, 20):
56             try:
57                 ids = str(datas[\"data\"][\"cards\"][i][\"mblog\"][\"user\"][\"id\"])    #获取用户id
58                 n_url2 = \'https://m.weibo.cn/api/container/getIndex?containerid=230283{}_-_INFO\'.format(ids)
59                 yield scrapy.Request(n_url2, meta={\'item\': item, \'ids\': copy.deepcopy(ids)}, callback=self.parse2)    #进入parse2函数执行命令
60             except IndexError or KeyError:
61                 pass
62         social_urls = [
63             \'https://m.weibo.cn/api/container/getIndex?containerid=102803_ctg1_4188_-_ctg1_4188&openApp=0&since_id={}\'.format(
64                 str(i)) for i in range(2, 100)]
65         celebritys_urls = [
66             \'https://m.weibo.cn/api/container/getIndex?containerid=102803_ctg1_4288_-_ctg1_4288&openApp=0&since_id={}\'.format(
67                 str(j)) for j in range(1, 100)]
68         hots_urls = [\'https://m.weibo.cn/api/container/getIndex?containerid=102803&openApp=0&since_id={}\'.format(str(t))
69                      for
70                      t in range(1, 100)]
71         urls = celebritys_urls + social_urls + hots_urls    #入口网址
72         for url in urls:
73             yield scrapy.Request(url, callback=self.parse)

这里要注意 scrpay.Request 函数的meta参数,它是一个字典,用来进行参数传递,如上面代码所示,我想在parse2()函数中用到parse()函数中爬取的用户id,就需要进行设置,这里就不过多解释了,其实我也是处于摸着石头过河的理解程度,想深入了解的朋友可自行百度。

  • 在setting.py配置爬虫

这次我只将内容导出到了csv文件中,方便后续筛选制作词云,如果爬取的数据较多的话,可以存储到数据库中。

 1 BOT_NAME = \'sinaweibo\'
 2 
 3 SPIDER_MODULES = [\'sinaweibo.spiders\']
 4 NEWSPIDER_MODULE = \'sinaweibo.spiders\'
 5 
 6 USER_AGENT: \'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36\'    #消息头
 7 DOWNLOAD_DELAY = 0.5    #延时0.5s
 8 # Crawl responsibly by identifying yourself (and your website) on the user-agent
 9 #USER_AGENT = \'sinaweibo (+http://www.yourdomain.com)\'
10 FEED_URI = \'file:C:/Users/lenovo/Desktop/weibo.csv\'    #存入文件位置
11 FEED_FORMAT = \'csv\'    #保存格式
12 ITEM_PIPELINES= {\'sinaweibo.pipelines.SinaweiboPipeline\': 300}     #管道设置
13 # Obey robots.txt rules
14 ROBOTSTXT_OBEY = False
15 FEED_EXPORT_ENCODING = \'UTF8\'   #编码格式

本次没有下载图片及其他内容了,因此pipelines.py文件就没有编写内容了。爬取的部分数据如下:

Scrapy爬取新浪微博移动版用户首页第一条微博

 

到这里爬虫部分就结束了,本次爬取的内容也较为简单,下面的话就是使用其中的部分数据来生成词云。

  • 词云制作

在文件中新建了一个 weibo_analysis.py 的文件,使用jieba库来进行分词,在此之前,需要先将所需数据提取出来,这里使用pandas就可以。

 这部分程序很简单,就不废话了,直接上代码:

 1 import csv
 2 import pandas as pd
 3 import jieba.analyse
 4 
 5 
 6 def get_ciyun(city):    #进行分词
 7     tags=jieba.analyse.extract_tags(str(city),topK=100,withWeight=True)
 8     for item in tags:
 9         print(item[0]+\'\\t\'+str(int(item[1]*1000)))
10 
11 
12 need_citys = [\'北京\', \'上海\', \'湖南\', \'四川\', \'广东\']
13 beijing = []
14 shanghai = []
15 hunan = []
16 sichuan = []
17 gd = []
18 pd.set_option(\'expand_frame_repr\', True)    #可换行显示
19 pd.set_option(\'display.max_rows\', None)    #显示所有行
20 pd.set_option(\'display.max_columns\', None)    #显示所有列
21 df = pd.read_csv(\'C:\\\\Users\\lenovo\\Desktop\\weibo.csv\')    #读取文件内容并转化为dataframes对象
22 
23 contents = df[\'first_news\']    #取微博内容
24 city = df[\'city\']    #取城市
25 for i in range(len(city)):
26     if need_citys[0] in city[i]:    #判断并存入
27         beijing.append(contents[i])
28     elif need_citys[1] in city[i]:
29         shanghai.append(contents[i])
30     elif need_citys[2] in city[i]:
31         hunan.append(contents[i])
32     elif need_citys[3] in city[i]:
33         sichuan.append(contents[i])
34     elif need_citys[4] in city[i]:
35         gd.append(contents[i])
36     else:
37         pass
38 
39 #输出
40 get_ciyun(beijing)
41 print(\'-\'*20)
42 get_ciyun(shanghai)
43 print(\'-\'*20)
44 get_ciyun(hunan)
45 print(\'-\'*20)
46 get_ciyun(sichuan)
47 print(\'-\'*20)
48 get_ciyun(gd)

本次是通过Tagul网站在制作词云,将上方输出的词频导入,选择好词云形状、字体(不支持中文可自行导入中文字体包)、颜色等点击可视化就能生成了,非常方便。

下面是我本次生成的词云图片:

Scrapy爬取新浪微博移动版用户首页第一条微博

 Scrapy爬取新浪微博移动版用户首页第一条微博

Scrapy爬取新浪微博移动版用户首页第一条微博

Scrapy爬取新浪微博移动版用户首页第一条微博

 

 

Scrapy爬取新浪微博移动版用户首页第一条微博

使用scrapy进行爬虫确实能大大提高爬取效率,同时本次使用过程中也发现了许多的问题,如对这个框架不够深入,还有很多方法不会用、不知道,还有就是Python本身的面向对象的知识理解的也不够,需要继续学习。这也说明了自己还只是一枚菜鸟。

若有疑问或建议,欢迎提出指正。

 

给TA打赏
共{{data.count}}人
人已打赏
随笔日记

使用Mybatis实现动态SQL(二)

2020-11-9 4:50:23

随笔日记

D3.js 区域生成器 (V3版本)

2020-11-9 4:50:25

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索