本此爬蟲採取scrapy框架進行編寫。
一站式獲取個人微博信息
1. 梳理爬蟲目的和思路
1.1 爬蟲的目的
- 爬取博主的個人信息,包括名字,微博認證內容,粉絲數,關注數等
- 爬取博主的關注列表,包括列表裏的每個人的個人信息
- 爬取博主的粉絲列表,包括列表裏的那個人的個人信息
- 爬取博主的微博內容,包括髮微博的時間,來源,圖片的鏈接,內容等
1.2 爬蟲的思路
- 分析網頁源碼,尋找其分裝json數據響應的Request URL的規律,得到其微博相關數據API
- 請求API,捕獲返回的json數據
- 分析這些json數據,提取自己有用的數據
- 將數據保存入數據庫
2. 分析網頁源碼
爬取的微博網址是手機端微博的登陸網址
2.1 分析博主信息網頁
該網頁是手機端微博登陸自己的微博後,打開自己的主頁,f12打開面板,直接查看XHR下的請求,因爲之前爬取過微博的爬蟲,採用的不是框架爬蟲,
Python幫你瞭解你喜歡的人!爬取她的微博內容信息!(Ajax數據爬取)
發現微博的數據是通過Ajax的方式加載的,故直接查看XHR下的響應,因爲是指爬取博主的個人信息,所以不用下拉頁面,直接f5刷新以下在出現的響應中進行爬取。很簡單就可以找見如圖所示的響應,發現個人信息就在data->user下,整體的數據返回格式是json,其RequestURL可以發現其就是最後的uid在發生變化
2.2 分析關注列表界面
點擊其關注就可以進入其關注列表頁面:
下拉頁面,就會看見出現的請求響應,很明顯這就是其加載關注列表的響應,分析其RequestURL鏈接,發現其請求變化的規律也是在於uid的變化和page的變化,其關注列表的信息在data->card_group中,列表中的每個人的信息在user中,其返回的數據格式也是json
2.3 粉絲列表頁面分析
點擊其粉絲便可進入其粉絲頁面:
下拉粉絲也面,在XHR下也會看見加載的響應,便是存儲粉絲列表的響應,其RequestURL鏈接的變化之初也是uid和since_id在變,一個標識用戶,一個改變頁數。其數據在data->cards下保存,每個粉絲的用戶信息在usr中保存,數據的返回格式也是JSON。
2.4 微博博文頁面分析
在其主頁面,點擊最下方的查看全部微博,便可以進入其微博博文頁面:
下拉頁面,在XHR下便可以看見加載的請求響應,其RequestURL的變化也是在於uid和page的變化,微博數據在data->cards->mblog中保存,整體的數據返回格式是JSON。
3. 得出2020年最新微博相關數據API
綜上所述,得出相關的微博相關數據的API:
# 用戶詳情API
user_url = 'https://m.weibo.cn/profile/info?uid={uid}'
# 關注列表API
follow_url = 'https://m.weibo.cn/api/container/getIndex?containerid=231051_-_followers_-_{uid}&page={page}'
# 粉絲列表API
fan_url = 'https://m.weibo.cn/api/container/getIndex?containerid=231051_-_fans_-_{uid}&since_id={page}'
# 微博內容API
weibo_url = 'https://m.weibo.cn/api/container/getIndex?containerid=230413{uid}_-_WEIBO_SECOND_PROFILE_WEIBO&page_type=03&page={page}'
4. 編寫代碼
4.1 創建Scrapy爬蟲項目
scrapy startproject weiboinfo
4.2 創建Spider
在Pycharm下端的Terminal中執行即可:
scrapy genspider weibo m.weibo.cn
4.3 根據網頁源碼下user下的信息,創建自己想提取的信息所對應的Item
在items.py下定義:
class UserItem(Item):
# define the fields for your item here like:
# name = scrapy.Field()
id = Field()
# 博主名字
screen_name = Field()
# 個人簡介
description = Field()
# 關注數
follow_count = Field()
# 粉絲數
followers_count = Field()
# 是否關注自己
follow_me = Field()
# 自己是否關注他
following = Field()
# 微博認證
verified_reason = Field()
# 微博鏈接
profile_url = Field()
# 全部微博數
statuses_count = Field()
class UserAttentionItem(Item):
id = Field()
# 博主名字
screen_name = Field()
# 關注數
follow_count = Field()
# 粉絲數
followers_count = Field()
# 是否關注自己
follow_me = Field()
# 自己是否關注他
following = Field()
# 微博鏈接
profile_url = Field()
class UserFansItem(Item):
id = Field()
# 博主名字
screen_name = Field()
# 關注數
follow_count = Field()
# 粉絲數
followers_count = Field()
# 微博鏈接
profile_url = Field()
# 微博簡介
desc1 = Field()
desc2 = Field()
class WeiboItem(Item):
id = Field()
# 點贊數
attitudes_count = Field()
# 評論數
comments_count = Field()
# pictuer 鏈接
picture_url = Field()
# 內容
raw_text = Field()
# 來源
source = Field()
# 發佈時間
created_at = Field()
4.4 進行數據的提取
4.4.1 創建程序的起始請求
class WeiboSpider(scrapy.Spider):
name = 'weibo'
allowed_domains = ['m.weibo.cn']
#start_urls = ['http://m.weibo.cn/']
# 這裏寫的是你想要爬取博主信息的uid
start_users = ['uid']
# 用戶詳情API
user_url = 'https://m.weibo.cn/profile/info?uid={uid}'
# 關注列表API
follow_url = 'https://m.weibo.cn/api/container/getIndex?containerid=231051_-_followers_-_{uid}&page={page}'
# 粉絲列表API
fan_url = 'https://m.weibo.cn/api/container/getIndex?containerid=231051_-_fans_-_{uid}&since_id={page}'
# 微博內容API
weibo_url = 'https://m.weibo.cn/api/container/getIndex?containerid=230413{uid}_-_WEIBO_SECOND_PROFILE_WEIBO&page_type=03&page={page}'
def start_requests(self):
for uid in self.start_users:
yield Request(self.user_url.format(uid=uid),callback=self.parse_user)
4.4.2 提取博主個人信息
'''
爬取博主個人信息
'''
def parse_user(self, response):
result = json.loads(response.text)
if result.get('data').get('user'):
user_info = result.get('data').get('user')
user_item = UserItem()
user_item['id'] = user_info.get('id')
user_item['screen_name'] = user_info.get('screen_name')
user_item['description'] = user_info.get('description')
user_item['follow_count'] = user_info.get('follow_count')
user_item['followers_count'] = user_info.get('followers_count')
user_item['follow_me'] = user_info.get('follow_me')
user_item['following'] = user_info.get('following')
user_item['verified_reason'] = user_info.get('verified_reason')
user_item['profile_url'] = user_info.get('profile_url')
user_item['statuses_count'] = user_info.get('statuses_count')
yield user_item
#獲取博主的id,進行構造下一項的請求
id = user_info.get('id')
# 關注
yield Request(self.follow_url.format(uid=id,page=1),callback=self.parse_follows,meta={'page':1,'uid':id})
# 粉絲
yield Request(self.fan_url.format(uid=id,page=1),callback=self.parse_fans,meta={'page':1,'uid':id})
# 微博
yield Request(self.weibo_url.format(uid=id,page=1),callback=self.parse_weibos,meta={'page':1,'uid':id})
4.4.3 提取博主關注列表及其用戶信息
'''
爬取博主關注列表信息
'''
def parse_follows(self,response):
result = json.loads(response.text)
if result.get('ok') and result.get('data').get('cards') and len(result.get('data').get('cards')) and result.get('data').get('cards')[-1].get('card_group'):
follows = result.get('data').get('cards')[-1].get('card_group')
for follow in follows:
if follow.get('user'):
uid = follow.get('user').get('id')
#yield Request(self.user_url.format(uid=uid),callback=self.parse_user)
user_AttentionItem = UserAttentionItem()
user_AttentionItem['id'] = follow.get('user').get('id')
user_AttentionItem['screen_name'] = follow.get('user').get('screen_name')
user_AttentionItem['follow_count'] = follow.get('user').get('follow_count')
user_AttentionItem['followers_count'] = follow.get('user').get('followers_count')
user_AttentionItem['follow_me'] = follow.get('user').get('follow_me')
user_AttentionItem['following'] = follow.get('user').get('following')
user_AttentionItem['profile_url'] = follow.get('user').get('profile_url')
yield user_AttentionItem
# 關注列表翻頁
uid = response.meta.get('uid')
page = response.meta.get('page') + 1
yield Request(self.follow_url.format(uid=uid,page=page),callback=self.parse_follows,meta={'page':page,'uid':uid})
4.4.4 提取博主粉絲列表及其用戶信息
'''
爬取博主粉絲列表信息
'''
def parse_fans(self,response):
result = json.loads(response.text)
if result.get('ok') and result.get('data').get('cards') and len(result.get('data').get('cards')) and result.get('data').get('cards')[-1].get('card_group'):
fans = result.get('data').get('cards')[-1].get('card_group')
for fan in fans:
if fan.get('user'):
uid = fan.get('user').get('id')
#yield Request(self.user_url.format(uid=uid),callback=self.parse_user)
# 分析列表
user_FansItem = UserFansItem()
user_FansItem['id'] = fan.get('user').get('id')
user_FansItem['screen_name'] = fan.get('user').get('screen_name')
user_FansItem['follow_count'] = fan.get('user').get('follow_count')
user_FansItem['followers_count'] = fan.get('user').get('followers_count')
user_FansItem['desc1'] = fan.get('desc1')
user_FansItem['desc2'] = fan.get('desc2')
user_FansItem['profile_url'] = fan.get('user').get('profile_url')
yield user_FansItem
# 分析列表 翻頁
uid = response.meta.get('uid')
page = response.meta.get('page') + 1
yield Request(self.fan_url.format(uid=uid,page=page),callback=self.parse_fans,meta={'page':page,'uid':uid})
4.4.5 提取博主微博內容
'''
爬取微博內容
'''
def parse_weibos(self,response):
result = json.loads(response.text)
if result.get('ok') and result.get('data').get('cards'):
weibos = result.get('data').get('cards')
for weibo in weibos[1::]:
mblog = weibo.get('mblog')
if mblog:
weibo_item = WeiboItem()
weibo_item['id'] = mblog.get('id')
weibo_item['attitudes_count'] = mblog.get('attitudes_count')
weibo_item['comments_count'] = mblog.get('comments_count')
weibo_item['picture_url'] = mblog.get('bmiddle_pic')
weibo_item['raw_text'] = mblog.get('raw_text')
weibo_item['source'] = mblog.get('source')
weibo_item['created_at'] = mblog.get('created_at')
yield weibo_item
# 微博內容翻頁
uid = response.meta.get('uid')
page = response.meta.get('page') + 1
yield Request(self.weibo_url.format(uid=uid,page=page),callback=self.parse_weibos,meta={'page':page,'uid':uid})
5. 建立相應的數據庫
數據庫中表的信息所建立的字段跟item中創建的Field一一對應即可。
5.1 數據庫如圖所示:
6. 連接數據庫並將數據存入數據庫
在 pipelines.py 中寫入如下代碼:
class PymysqlPipeline(object):
#連接數據庫
def __init__(self):
self.connect = pymysql.connect(
host = 'localhost',
database = 'weibo',
user = 'root',
password = '123456',
charset = 'utf8',
port = 3306
)
# 創建遊標對象
self.cursor = self.connect.cursor()
# 此方法是必須要實現的方法,被定義的 Item Pipeline 會默認調用這個方法對 Item 進行處理
def process_item(self,item,spider):
# 判斷item是哪一類的item
if isinstance(item,UserItem):
cursor = self.cursor
sql = 'insert into userItem(id,screen_name,description,follow_count,followers_count,follow_me,following,verified_reason,statuses_count,url) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
cursor.execute(sql,(
item['id'],item['screen_name'],item['description'],item['follow_count'],item['followers_count'],item['follow_me'],item['following'],item['verified_reason'],item['statuses_count'],item['profile_url']
))
# 提交數據庫事務
self.connect.commit()
return item
if isinstance(item,UserAttentionItem):
cursor = self.cursor
sql = 'insert into userAttentionItem(uid,screen_name,follow_count,followers_count,follow_me,following,profile_url) values (%s,%s,%s,%s,%s,%s,%s)'
cursor.execute(sql,(
item['id'],item['screen_name'],item['follow_count'],item['followers_count'],item['follow_me'],item['following'],item['profile_url']
))
#提交數據庫事務
self.connect.commit()
return item
if isinstance(item,UserFansItem):
cursor = self.cursor
sql = 'insert into userfansitem(id,screen_name,follow_count,followers_count,desc1,desc2,profile_url) values (%s,%s,%s,%s,%s,%s,%s)'
cursor.execute(sql,(
item['id'],item['screen_name'],item['follow_count'],item['followers_count'],item['desc1'],item['desc2'],item['profile_url']
))
self.connect.commit()
return item
if isinstance(item,WeiboItem):
cursor = self.cursor
sql = 'insert into weiboitem(id,attitudes_count,comments_count,picture_url,raw_text,source,created_at) values (%s,%s,%s,%s,%s,%s,%s)'
cursor.execute(sql,(
item['id'],item['attitudes_count'],item['comments_count'],item['picture_url'],item['raw_text'],item['source'],item['created_at']
))
self.connect.commit()
return item
6.1 啓動pipline
#開啓自己寫的 Pipeline
ITEM_PIPELINES = {
'weiboinfo.pipelines.PymysqlPipeline':300
}
7. 套娃、批量式獲取微博用戶信息
這個功能在上述的代碼編寫的時候就已經實現了,由於是不斷的迭代爬取,後臺在一直出現數據,按理來說是很難自動停下來的,所以我將構建迭代請求的代碼註釋掉,次全部代碼的功能爲分析一個人的微博用戶,可以爬取其個人信息,關注列表,粉絲列表,所發的微博內容信息。
不想迭代式爬取的第二個原因是,存儲困難,mysql數據庫無法按自己的想法存儲對應的信息,比如,我想對兩位博主的信息進行爬取,將兩位博主各自的關注列表,粉絲列表各存儲到一個表當中,但是因爲公用的是一個item,無法實現分別存放,只能生硬的存放到一個表當中,存儲的方式感覺不是很得當,或者是自己沒有想到更好的解決方法…
若想實現套娃、迭代式的爬取,只需將如下圖的代碼接觸註釋即可:
8. 代碼存在的問題
此代碼,在反爬方面僅在setting.py當中添加了不同的headers,和構造了基礎的請求頭信息,自己在迭代爬取的過程當中發現,當爬取的數據一次性超過1100條以上,自己的ip地址將會被短暫的禁止訪問網頁,所以這裏的反爬做的很是不好,自己還得努力,爭取學會搭建cookies池…
9. 爬取的結果
9.1 後臺結果
9.2 數據庫結果
代碼中有出現的錯誤和什麼論述不對的地方,請評論或私信指出我立馬改正。
大家有什麼好的建議也可以評論或私信指出,小白接受任何批評😁