前面講解了Scrapy中各個模組基本使用方法以及代理池、Cookies池。接下來我們以一個反爬比較強的網站新浪微博為例,來實現一下Scrapy的大規模爬取。
一、本節目標
本次爬取的目標是新浪微博使用者的公開基本資訊,如使用者暱稱、頭像、使用者的關注、粉絲列表以及釋出的微博等,這些資訊抓取之後儲存至MongoDB。
二、準備工作
請確保前文所講的代理池、Cookies池已經實現並可以正常執行,安裝Scrapy、PyMongo庫。
三、爬取思路
首先我們要實現使用者的大規模爬取。這裡採用的爬取方式是,以微博的幾個大V為起始點,爬取他們各自的粉絲和關注列表,然後獲取粉絲和關注列表的粉絲和關注列表,以此類推,這樣下去就可以實現遞迴爬取。如果一個使用者與其他使用者有社交網路上的關聯,那他們的資訊就會被爬蟲抓取到,這樣我們就可以做到對所有使用者的爬取。通過這種方式,我們可以得到使用者的唯一ID,再根據ID獲取每個使用者釋出的微博即可。
四、爬取分析
這裡我們選取的爬取站點是:https://m.weibo.cn,此站點是微博移動端的站點。開啟該站點會跳轉到登入頁面,這是因為主頁做了登入限制。不過我們可以繞過登入限制,直接開啟某個使用者詳情頁面,例如開啟周冬雨的微博,連結為:https://m.weibo.cn/u/1916655407,即可進入其個人詳情頁面,如下圖所示。
我們在頁面最上方可以看到周冬雨的關注和粉絲數量。我們點選關注,進入到她的關注列表,如下圖所示。
我們開啟開發者工具,切換到XHR過濾器,一直下拉關注列表,即可看到下方會出現很多Ajax請求,這些請求就是獲取周冬雨的關注列表的Ajax請求,如下圖所示。
我們開啟第一個Ajax請求,它的連結為:https://m.weibo.cn/api/container/getIndex?containerid=231051
請求型別是GET型別,返回結果是JSON格式,我們將其展開之後即可看到其關注的使用者的基本資訊。接下來我們只需要構造這個請求的引數。此連結一共有7個引數,如下圖所示。
其中最主要的引數就是containerid
和page
。有了這兩個引數,我們同樣可以獲取請求結果。我們可以將介面精簡為:https://m.weibo.cn/api/container/getIndex?containerid=231051
container_id
的前半部分是固定的,後半部分是使用者的id。所以這裡引數就可以構造出來了,只需要修改container_id
最後的id
和page
引數即可獲取分頁形式的關注列表資訊。利用同樣的方法,我們也可以分析使用者詳情的Ajax連結、使用者微博列表的Ajax連結,如下所示:
# 使用者詳情API
user_url = 'https://m.weibo.cn/api/container/getIndex?uid={uid}&type=uid&value={uid}&containerid=100505{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}&page={page}'
# 微博列表API
weibo_url = 'https://m.weibo.cn/api/container/getIndex?uid={uid}&type=uid&page={page}&containerid=107603{uid}'複製程式碼
此處的uid
和page
分別代表使用者ID和分頁頁碼。
注意,這個API可能隨著時間的變化或者微博的改版而變化,以實測為準。
我們從幾個大V開始抓取,抓取他們的粉絲、關注列表、微博資訊,然後遞迴抓取他們的粉絲和關注列表的粉絲、關注列表、微博資訊,遞迴抓取,最後儲存微博使用者的基本資訊、關注和粉絲列表、釋出的微博。
我們選擇MongoDB作儲存的資料庫,可以更方便地儲存使用者的粉絲和關注列表。
五、新建專案
接下來我們用Scrapy來實現這個抓取過程。首先建立一個專案,命令如下所示:
scrapy startproject weibo複製程式碼
進入專案中,新建一個Spider,名為weibocn,命令如下所示:
scrapy genspider weibocn m.weibo.cn複製程式碼
我們首先修改Spider,配置各個Ajax的URL,選取幾個大V,將他們的ID賦值成一個列表,實現start_requests()
方法,也就是依次抓取各個大V的個人詳情,然後用parse_user()
進行解析,如下所示:
from scrapy import Request, Spider
class WeiboSpider(Spider):
name = 'weibocn'
allowed_domains = ['m.weibo.cn']
user_url = 'https://m.weibo.cn/api/container/getIndex?uid={uid}&type=uid&value={uid}&containerid=100505{uid}'
follow_url = 'https://m.weibo.cn/api/container/getIndex?containerid=231051_-_followers_-_{uid}&page={page}'
fan_url = 'https://m.weibo.cn/api/container/getIndex?containerid=231051_-_fans_-_{uid}&page={page}'
weibo_url = 'https://m.weibo.cn/api/container/getIndex?uid={uid}&type=uid&page={page}&containerid=107603{uid}'
start_users = ['3217179555', '1742566624', '2282991915', '1288739185', '3952070245', '5878659096']
def start_requests(self):
for uid in self.start_users:
yield Request(self.user_url.format(uid=uid), callback=self.parse_user)
def parse_user(self, response):
self.logger.debug(response)複製程式碼
六、建立Item
接下來我們解析使用者的基本資訊並生成Item。這裡我們先定義幾個Item,如使用者、使用者關係、微博的Item,如下所示:
from scrapy import Item, Field
class UserItem(Item):
collection = 'users'
id = Field()
name = Field()
avatar = Field()
cover = Field()
gender = Field()
description = Field()
fans_count = Field()
follows_count = Field()
weibos_count = Field()
verified = Field()
verified_reason = Field()
verified_type = Field()
follows = Field()
fans = Field()
crawled_at = Field()
class UserRelationItem(Item):
collection = 'users'
id = Field()
follows = Field()
fans = Field()
class WeiboItem(Item):
collection = 'weibos'
id = Field()
attitudes_count = Field()
comments_count = Field()
reposts_count = Field()
picture = Field()
pictures = Field()
source = Field()
text = Field()
raw_text = Field()
thumbnail = Field()
user = Field()
created_at = Field()
crawled_at = Field()複製程式碼
這裡定義了collection
欄位,指明儲存的Collection的名稱。使用者的關注和粉絲列表直接定義為一個單獨的UserRelationItem
,其中id
就是使用者的ID,follows
就是使用者關注列表,fans
是粉絲列表,但這並不意味著我們會將關注和粉絲列表存到一個單獨的Collection裡。後面我們會用Pipeline對各個Item進行處理、合併儲存到使用者的Collection裡,因此Item和Collection並不一定是完全對應的。
七、提取資料
我們開始解析使用者的基本資訊,實現parse_user()
方法,如下所示:
def parse_user(self, response):
"""
解析使用者資訊
:param response: Response物件
"""
result = json.loads(response.text)
if result.get('data').get('userInfo'):
user_info = result.get('data').get('userInfo')
user_item = UserItem()
field_map = {
'id': 'id', 'name': 'screen_name', 'avatar': 'profile_image_url', 'cover': 'cover_image_phone',
'gender': 'gender', 'description': 'description', 'fans_count': 'followers_count',
'follows_count': 'follow_count', 'weibos_count': 'statuses_count', 'verified': 'verified',
'verified_reason': 'verified_reason', 'verified_type': 'verified_type'
}
for field, attr in field_map.items():
user_item[field] = user_info.get(attr)
yield user_item
# 關注
uid = user_info.get('id')
yield Request(self.follow_url.format(uid=uid, page=1), callback=self.parse_follows,
meta={'page': 1, 'uid': uid})
# 粉絲
yield Request(self.fan_url.format(uid=uid, page=1), callback=self.parse_fans,
meta={'page': 1, 'uid': uid})
# 微博
yield Request(self.weibo_url.format(uid=uid, page=1), callback=self.parse_weibos,
meta={'page': 1, 'uid': uid})複製程式碼
在這裡我們一共完成了兩個操作。
解析JSON提取使用者資訊並生成UserItem返回。我們並沒有採用常規的逐個賦值的方法,而是定義了一個欄位對映關係。我們定義的欄位名稱可能和JSON中使用者的欄位名稱不同,所以在這裡定義成一個字典,然後遍歷字典的每個欄位實現逐個欄位的賦值。
構造使用者的關注、粉絲、微博的第一頁的連結,並生成Request,這裡需要的引數只有使用者的ID。另外,初始分頁頁碼直接設定為1即可。
接下來,我們還需要儲存使用者的關注和粉絲列表。以關注列表為例,其解析方法為parse_follows()
,實現如下所示:
def parse_follows(self, response):
"""
解析使用者關注
:param response: 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)
# 關注列表
uid = response.meta.get('uid')
user_relation_item = UserRelationItem()
follows = [{'id': follow.get('user').get('id'), 'name': follow.get('user').get('screen_name')} for follow in
follows]
user_relation_item['id'] = uid
user_relation_item['follows'] = follows
user_relation_item['fans'] = []
yield user_relation_item
# 下一頁關注
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})複製程式碼
那麼在這個方法裡面我們做了如下三件事。
解析關注列表中的每個使用者資訊併發起新的解析請求。我們首先解析關注列表的資訊,得到使用者的ID,然後再利用
user_url
構造訪問使用者詳情的Request,回撥就是剛才所定義的parse_user()
方法。提取使用者關注列表內的關鍵資訊並生成
UserRelationItem
。id
欄位直接設定成使用者的ID,JSON返回資料中的使用者資訊有很多冗餘欄位。在這裡我們只提取了關注使用者的ID和使用者名稱,然後把它們賦值給follows
欄位,fans
欄位設定成空列表。這樣我們就建立了一個存有使用者ID和使用者部分關注列表的UserRelationItem
,之後合併且儲存具有同一個ID的UserRelationItem
的關注和粉絲列表。提取下一頁關注。只需要將此請求的分頁頁碼加1即可。分頁頁碼通過Request的
meta
屬性進行傳遞,Response的meta
來接收。這樣我們構造並返回下一頁的關注列表的Request。
抓取粉絲列表的原理和抓取關注列表原理相同,在此不再贅述。
接下來我們還差一個方法的實現,即parse_weibos()
,它用來抓取使用者的微博資訊,實現如下所示:
def parse_weibos(self, response):
"""
解析微博列表
:param response: 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:
mblog = weibo.get('mblog')
if mblog:
weibo_item = WeiboItem()
field_map = {
'id': 'id', 'attitudes_count': 'attitudes_count', 'comments_count': 'comments_count', 'created_at': 'created_at',
'reposts_count': 'reposts_count', 'picture': 'original_pic', 'pictures': 'pics',
'source': 'source', 'text': 'text', 'raw_text': 'raw_text', 'thumbnail': 'thumbnail_pic'
}
for field, attr in field_map.items():
weibo_item[field] = mblog.get(attr)
weibo_item['user'] = response.meta.get('uid')
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={'uid': uid, 'page': page})複製程式碼
在這裡parse_weibos()
方法完成了兩件事。
提取使用者的微博資訊,並生成WeiboItem。這裡同樣建立了一個欄位對映表,實現批量欄位賦值。
提取下一頁的微博列表。這裡同樣需要傳入使用者ID和分頁頁碼。
目前為止,微博的Spider已經完成。後面還需要對資料進行資料清洗儲存,以及對接代理池、Cookies池來防止反爬蟲。
八、資料清洗
有些微博的時間可能不是標準的時間,比如它可能顯示為剛剛、幾分鐘前、幾小時前、昨天等。這裡我們需要統一轉化這些時間,實現一個parse_time()
方法,如下所示:
def parse_time(self, date):
if re.match('剛剛', date):
date = time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time()))
if re.match('\d+分鐘前', date):
minute = re.match('(\d+)', date).group(1)
date = time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time() - float(minute) * 60))
if re.match('\d+小時前', date):
hour = re.match('(\d+)', date).group(1)
date = time.strftime('%Y-%m-%d %H:%M', time.localtime(time.time() - float(hour) * 60 * 60))
if re.match('昨天.*', date):
date = re.match('昨天(.*)', date).group(1).strip()
date = time.strftime('%Y-%m-%d', time.localtime() - 24 * 60 * 60) + ' ' + date
if re.match('\d{2}-\d{2}', date):
date = time.strftime('%Y-', time.localtime()) + date + ' 00:00'
return date複製程式碼
我們用正則來提取一些關鍵數字,用time庫來實現標準時間的轉換。
以X分鐘前的處理為例,爬取的時間會賦值為created_at
欄位。我們首先用正則匹配這個時間,表示式寫作\d+分鐘前
,如果提取到的時間符合這個表示式,那麼就提取出其中的數字,這樣就可以獲取分鐘數了。接下來使用time
模組的strftime()
方法,第一個引數傳入要轉換的時間格式,第二個引數就是時間戳。在這裡我們用當前的時間戳減去此分鐘數乘以60就是當時的時間戳,這樣我們就可以得到格式化後的正確時間了。
然後Pipeline可以實現如下處理:
class WeiboPipeline():
def process_item(self, item, spider):
if isinstance(item, WeiboItem):
if item.get('created_at'):
item['created_at'] = item['created_at'].strip()
item['created_at'] = self.parse_time(item.get('created_at'))複製程式碼
我們在Spider裡沒有對crawled_at
欄位賦值,它代表爬取時間,我們可以統一將其賦值為當前時間,實現如下所示:
class TimePipeline():
def process_item(self, item, spider):
if isinstance(item, UserItem) or isinstance(item, WeiboItem):
now = time.strftime('%Y-%m-%d %H:%M', time.localtime())
item['crawled_at'] = now
return item複製程式碼
在這裡我們判斷了Item如果是UserItem或WeiboItem型別,那麼就給它的crawled_at
欄位賦值為當前時間。
通過上面的兩個Pipeline,我們便完成了資料清洗工作,這裡主要是時間的轉換。
九、資料儲存
資料清洗完畢之後,我們就要將資料儲存到MongoDB資料庫。我們在這裡實現MongoPipeline類,如下所示:
import pymongo
class MongoPipeline(object):
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'), mongo_db=crawler.settings.get('MONGO_DATABASE')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
self.db[UserItem.collection].create_index([('id', pymongo.ASCENDING)])
self.db[WeiboItem.collection].create_index([('id', pymongo.ASCENDING)])
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
if isinstance(item, UserItem) or isinstance(item, WeiboItem):
self.db[item.collection].update({'id': item.get('id')}, {'$set': item}, True)
if isinstance(item, UserRelationItem):
self.db[item.collection].update(
{'id': item.get('id')},
{'$addToSet':
{
'follows': {'$each': item['follows']},
'fans': {'$each': item['fans']}
}
}, True)
return item複製程式碼
當前的MongoPipeline和前面我們所寫的有所不同,主要有以下幾點。
open_spider()
方法裡新增了Collection的索引,在這裡為兩個Item都新增了索引,索引的欄位是id
。由於我們這次是大規模爬取,爬取過程涉及資料的更新問題,所以我們為每個Collection建立了索引,這樣可以大大提高檢索效率。在
process_item()
方法裡儲存使用的是update()
方法,第一個引數是查詢條件,第二個引數是爬取的Item。這裡我們使用了$set
操作符,如果爬取到重複的資料即可對資料進行更新,同時不會刪除已存在的欄位。如果這裡不加$set
操作符,那麼會直接進行item
替換,這樣可能會導致已存在的欄位如關注和粉絲列表清空。第三個引數設定為True,如果資料不存在,則插入資料。這樣我們就可以做到資料存在即更新、資料不存在即插入,從而獲得去重的效果。對於使用者的關注和粉絲列表,我們使用了一個新的操作符,叫作
$addToSet
,這個操作符可以向列表型別的欄位插入資料同時去重。它的值就是需要操作的欄位名稱。這裡利用了$each
操作符對需要插入的列表資料進行了遍歷,以逐條插入使用者的關注或粉絲資料到指定的欄位。關於該操作更多解釋可以參考MongoDB的官方文件,連結為:https://docs.mongodb.com/manual/reference/operator/update/addToSet/。
十、Cookies池對接
新浪微博的反爬能力非常強,我們需要做一些防範反爬蟲的措施才可以順利完成資料爬取。
如果沒有登入而直接請求微博的API介面,這非常容易導致403狀態碼。這個情況我們在Cookies池一節也提過。所以在這裡我們實現一個Middleware,為每個Request新增隨機的Cookies。
我們先開啟Cookies池,使API模組正常執行。例如在本地執行5000埠,訪問:http://localhost:5000/weibo/random,即可獲取隨機的Cookies。當然也可以將Cookies池部署到遠端的伺服器,這樣只需要更改訪問的連結。
我們在本地啟動Cookies池,實現一個Middleware,如下所示:
class CookiesMiddleware():
def __init__(self, cookies_url):
self.logger = logging.getLogger(__name__)
self.cookies_url = cookies_url
def get_random_cookies(self):
try:
response = requests.get(self.cookies_url)
if response.status_code == 200:
cookies = json.loads(response.text)
return cookies
except requests.ConnectionError:
return False
def process_request(self, request, spider):
self.logger.debug('正在獲取Cookies')
cookies = self.get_random_cookies()
if cookies:
request.cookies = cookies
self.logger.debug('使用Cookies ' + json.dumps(cookies))
@classmethod
def from_crawler(cls, crawler):
settings = crawler.settings
return cls(
cookies_url=settings.get('COOKIES_URL')
)複製程式碼
我們首先利用from_crawler()
方法獲取了COOKIES_URL
變數,它定義在settings.py裡,這就是剛才我們所說的介面。接下來實現get_random_cookies()
方法,這個方法主要就是請求此Cookies池介面並獲取介面返回的隨機Cookies。如果成功獲取,則返回Cookies;否則返回False
。
接下來,在process_request()
方法裡,我們給request
物件的cookies
屬性賦值,其值就是獲取的隨機Cookies,這樣我們就成功地為每一次請求賦值Cookies了。
如果啟用了該Middleware,每個請求都會被賦值隨機的Cookies。這樣我們就可以模擬登入之後的請求,403狀態碼基本就不會出現。
十一、代理池對接
微博還有一個反爬措施就是,檢測到同一IP請求量過大時就會出現414狀態碼。如果遇到這樣的情況可以切換代理。例如,在本地5555埠執行,獲取隨機可用代理的地址為:http://localhost:5555/random,訪問這個介面即可獲取一個隨機可用代理。接下來我們再實現一個Middleware,程式碼如下所示:
class ProxyMiddleware():
def __init__(self, proxy_url):
self.logger = logging.getLogger(__name__)
self.proxy_url = proxy_url
def get_random_proxy(self):
try:
response = requests.get(self.proxy_url)
if response.status_code == 200:
proxy = response.text
return proxy
except requests.ConnectionError:
return False
def process_request(self, request, spider):
if request.meta.get('retry_times'):
proxy = self.get_random_proxy()
if proxy:
uri = 'https://{proxy}'.format(proxy=proxy)
self.logger.debug('使用代理 ' + proxy)
request.meta['proxy'] = uri
@classmethod
def from_crawler(cls, crawler):
settings = crawler.settings
return cls(
proxy_url=settings.get('PROXY_URL')
)複製程式碼
同樣的原理,我們實現了一個get_random_proxy()
方法用於請求代理池的介面獲取隨機代理。如果獲取成功,則返回改代理,否則返回False
。在process_request()
方法中,我們給request
物件的meta
屬性賦值一個proxy
欄位,該欄位的值就是代理。
另外,賦值代理的判斷條件是當前retry_times
不為空,也就是說第一次請求失敗之後才啟用代理,因為使用代理後訪問速度會慢一些。所以我們在這裡設定了只有重試的時候才啟用代理,否則直接請求。這樣就可以保證在沒有被封禁的情況下直接爬取,保證了爬取速度。
十二、啟用Middleware
接下來,我們在配置檔案中啟用這兩個Middleware,修改settings.py如下所示:
DOWNLOADER_MIDDLEWARES = {
'weibo.middlewares.CookiesMiddleware': 554,
'weibo.middlewares.ProxyMiddleware': 555,
}複製程式碼
注意這裡的優先順序設定,前文提到了Scrapy的預設Downloader Middleware的設定如下:
{
'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
}複製程式碼
要使得我們自定義的CookiesMiddleware生效,它在內建的CookiesMiddleware之前呼叫。內建的CookiesMiddleware的優先順序為700,所以這裡我們設定一個比700小的數字即可。
要使得我們自定義的ProxyMiddleware生效,它在內建的HttpProxyMiddleware之前呼叫。內建的HttpProxyMiddleware的優先順序為750,所以這裡我們設定一個比750小的數字即可。
十三、執行
到此為止,整個微博爬蟲就實現完畢了。我們執行如下命令啟動爬蟲:
scrapy crawl weibocn複製程式碼
輸出結果如下所示:
2017-07-11 17:27:34 [urllib3.connectionpool] DEBUG: http://localhost:5000 "GET /weibo/random HTTP/1.1" 200 339
2017-07-11 17:27:34 [weibo.middlewares] DEBUG: 使用Cookies {"SCF": "AhzwTr_DxIGjgri_dt46_DoPzUqq-PSupu545JdozdHYJ7HyEb4pD3pe05VpbIpVyY1ciKRRWwUgojiO3jYwlBE.", "_T_WM": "8fe0bc1dad068d09b888d8177f1c1218", "SSOLoginState": "1501496388", "M_WEIBOCN_PARAMS": "uicode%3D20000174", "SUHB": "0tKqV4asxqYl4J", "SUB": "_2A250e3QUDeRhGeBM6VYX8y7NwjiIHXVXhBxcrDV6PUJbkdBeLXjckW2fUT8MWloekO4FCWVlIYJGJdGLnA.."}
2017-07-11 17:27:34 [weibocn] DEBUG: <200 https://m.weibo.cn/api/container/getIndex?uid=1742566624&type=uid&value=1742566624&containerid=1005051742566624>
2017-07-11 17:27:34 [scrapy.core.scraper] DEBUG: Scraped from <200 https://m.weibo.cn/api/container/getIndex?uid=1742566624&type=uid&value=1742566624&containerid=1005051742566624>
{'avatar': 'https://tva4.sinaimg.cn/crop.0.0.180.180.180/67dd74e0jw1e8qgp5bmzyj2050050aa8.jpg',
'cover': 'https://tva3.sinaimg.cn/crop.0.0.640.640.640/6ce2240djw1e9oaqhwllzj20hs0hsdir.jpg',
'crawled_at': '2017-07-11 17:27',
'description': '成長,就是一個不斷覺得以前的自己是個傻逼的過程',
'fans_count': 19202906,
'follows_count': 1599,
'gender': 'm',
'id': 1742566624,
'name': '思想聚焦',
'verified': True,
'verified_reason': '微博知名博主,校導網編輯',
'verified_type': 0,
'weibos_count': 58393}複製程式碼
執行一段時間後,我們便可以到MongoDB資料庫檢視資料,爬取下來的資料如下圖所示。
針對使用者資訊,我們不僅爬取了其基本資訊,還把關注和粉絲列表加到了follows
和fans
欄位並做了去重操作。針對微博資訊,我們成功進行了時間轉換處理,同時還儲存了微博的圖片列表資訊。
十四、本節程式碼
本節程式碼地址為:https://github.com/Python3WebSpider/Weibo。
十五、結語
本節實現了新浪微博的使用者及其粉絲關注列表和微博資訊的爬取,還對接了Cookies池和代理池來處理反爬蟲。不過現在是針對單機的爬取,後面我們會將此專案修改為分散式爬蟲,以進一步提高抓取效率。
本資源首發於崔慶才的個人部落格靜覓: Python3網路爬蟲開發實戰教程 | 靜覓
如想了解更多爬蟲資訊,請關注我的個人微信公眾號:進擊的Coder
weixin.qq.com/r/5zsjOyvEZ… (二維碼自動識別)