Scrapy爬取新浪微博移動版用戶首頁第一條微博


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

最近找了一份關於爬蟲的實習工作,需要爬取較大量的數據,這時就發現通過自己編寫函數來實現爬蟲效率太慢了;於是又轉回來用scrapy,以前稍微學習了一下,這次剛好爬爬微博練練手,而后再使用部分數據生成詞雲。

本次爬取的是新浪微博移動端(https://m.weibo.cn/),爬取的數據是用戶微博首頁的第一條微博(如下圖),包括文字內容、轉發量、評論數、點贊數和發布時間,還有用戶名和其所在地區(后面可以分析不同地區微博用戶的關心的熱點話題)。

 

一、分析網頁


 

  • 獲取用戶微博入口url

瀏覽發現使用的是使用Ajax渲染的網頁,微博數據(https://m.weibo.cn/api/container/getIndex?containerid=102803_ctg1_5088_-_ctg1_5088&openApp=0&since_id=1)存儲在json格式網頁中,所以思路是先通過微博數據得到用戶url(如下圖),再來爬取后續內容。

  •  獲取第一條微博數據

也是使用了Ajax渲染的網頁,跟上面一樣找到網頁入口就行了。請求網址如下:

這樣看網址的話毫無規律可言,簡化后發現 https://m.weibo.cn/api/container/getIndex?containerid=1076032554757470就可以進入。而且containerid=107603(***)這里,括號里的數字剛好是用戶的id號,因此我們可以通過這個來構造網頁。

  • 獲取用戶所在地區

用戶所在地在其基本資料中,如下圖

地址為:

同樣進行簡化得到: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文件就沒有編寫內容了。爬取的部分數據如下:


 

到這里爬蟲部分就結束了,本次爬取的內容也較為簡單,下面的話就是使用其中的部分數據來生成詞雲。

  • 詞雲制作

在文件中新建了一個 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進行爬蟲確實能大大提高爬取效率,同時本次使用過程中也發現了許多的問題,如對這個框架不夠深入,還有很多方法不會用、不知道,還有就是Python本身的面向對象的知識理解的也不夠,需要繼續學習。這也說明了自己還只是一枚菜鳥。

若有疑問或建議,歡迎提出指正。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM