前面講解了 Scrapy 中各個模組基本使用方法以及代理池、Cookies 池。接下來我們以一個反爬比較強的網站新浪微博爲例,來實現一下 Scrapy 的大規模爬取。
很多人學習python,不知道從何學起。
很多人學習python,掌握了基本語法過後,不知道在哪裏尋找案例上手。
很多已經做案例的人,卻不知道如何去學習更加高深的知識。
那麼針對這三類人,我給大家提供一個好的學習平臺,免費領取視訊教學,電子書籍,以及課程的原始碼!
QQ羣:101677771
本次爬取的目標是新浪微博使用者的公開基本資訊,如使用者暱稱、頭像、使用者的關注、粉絲列表以及發佈的微博等,這些資訊抓取之後儲存至 MongoDB。
請確保前文所講的代理池、Cookies 池已經實現並可以正常執行,安裝 Scrapy、PyMongo 庫,如沒有安裝可以參考前文內容。
首先我們要實現使用者的大規模爬取。這裏採用的爬取方式是,以微博的幾個大 V 爲起始點,爬取他們各自的粉絲和關注列表,然後獲取粉絲和關注列表的粉絲和關注列表,以此類推,這樣下去就可以實現遞回爬取。如果一個使用者與其他使用者有社羣網路上的關聯,那他們的資訊就會被爬蟲抓取到,這樣我們就可以做到對所有使用者的爬取。通過這種方式,我們可以得到使用者的唯一 ID,再根據 ID 獲取每個使用者發佈的微博即可。
這裏我們選取的爬取站點是:https://m.weibo.cn,此站點是微博行動端的站點。開啓該站點會跳轉到登錄頁面,這是因爲主頁做了登錄限制。不過我們可以直接開啓某個使用者詳情頁面,如圖 13-32 所示。
圖 13-32 個人詳情頁面
我們在頁面最上方可以看到她的關注和粉絲數量。我們點選關注,進入到她的關注列表,如圖 13-33 所示。
圖 13-33 關注列表
我們開啓開發者工具,切換到 XHR 過濾器,一直下拉關注列表,即可看到下方會出現很多 Ajax 請求,這些請求就是獲取關注列表的 Ajax 請求,如圖 13-34 所示。
圖 13-34 請求列表
我們開啓第一個 Ajax 請求看一下,發現它的鏈接爲:https://m.weibo.cn/api/container/getIndex?containerid=231051_-_followers_-_1916655407&luicode=10000011&lfid=1005051916655407&featurecode=20000320&type=uid&value=1916655407&page=2,詳情如圖 13-35 和 13-36 所示。
圖 13-35 請求詳情
圖 13-36 響應結果
請求型別是 GET 型別,返回結果是 JSON 格式,我們將其展開之後即可看到其關注的使用者的基本資訊。接下來我們只需要構造這個請求的參數。此鏈接一共有 7 個參數,如圖 13-37 所示。
圖 13-37 參數資訊
其中最主要的參數就是 containerid 和 page。有了這兩個參數,我們同樣可以獲取請求結果。我們可以將介面精簡爲:https://m.weibo.cn/api/container/getIndex?containerid=231051_-_followers_-_1916655407&page=2,這裏的 containerid 的前半部分是固定的,後半部分是使用者的 id。所以這裏參數就可以構造出來了,只需要修改 containerid 最後的 id 和 page 參數即可獲取分頁形式的關注列表資訊。
利用同樣的方法,我們也可以分析使用者詳情的 Ajax 鏈接、使用者微博列表的 Ajax 鏈接,如下所示:
1 2 3 4 5 6 7 8 |
# 使用者詳情 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 來實現這個抓取過程。首先建立一個專案,命令如下所示:
1 |
scrapy startproject weibo |
進入專案中,新建一個 Spider,名爲 weibocn,命令如下所示:
1 |
scrapy genspider weibocn m.weibo.cn |
我們首先修改 Spider,設定各個 Ajax 的 URL,選取幾個大 V,將他們的 ID 賦值成一個列表,實現 start_requests() 方法,也就是依次抓取各個大 V 的個人詳情,然後用 parse_user() 進行解析,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
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() 方法,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
def parse_user(self, response): """ 解析使用者資訊 :param response: Response 物件 """ result = json.loads(response.text) if result.get('userInfo'): user_info = result.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}) |
在這裏我們一共完成了兩個操作。
接下來,我們還需要儲存使用者的關注和粉絲列表。以關注列表爲例,其解析方法爲 parse_follows(),實現如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
def parse_follows(self, response): """ 解析使用者關注 :param response: Response 物件 """ result = json.loads(response.text) if result.get('ok') and result.get('cards') and len(result.get('cards')) and result.get('cards')[-1].get('card_group'): # 解析使用者 follows = result.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}) |
那麼在這個方法裏面我們做瞭如下三件事。
抓取粉絲列表的原理和抓取關注列表原理相同,在此不再贅述。
接下來我們還差一個方法的實現,即 parse_weibos(),它用來抓取使用者的微博資訊,實現如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
def parse_weibos(self, response): """ 解析微博列表 :param response: Response 物件 """ result = json.loads(response.text) if result.get('ok') and result.get('cards'): weibos = result.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() 方法完成了兩件事。
到目前爲止,微博的 Spider 已經完成。後面還需要對數據進行數據清洗儲存,以及對接代理池、Cookies 池來防止反爬蟲。
有些微博的時間可能不是標準的時間,比如它可能顯示爲剛剛、幾分鐘前、幾小時前、昨天等。這裏我們需要統一轉化這些時間,實現一個 parse_time() 方法,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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 可以實現如下處理:
1 2 3 4 5 6 |
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 欄位賦值,它代表爬取時間,我們可以統一將其賦值爲當前時間,實現如下所示:
1 2 3 4 5 6 |
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 類,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
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 和前面我們所寫的有所不同,主要有以下幾點。
新浪微博的反爬能力非常強,我們需要做一些防範反爬蟲的措施纔可以順利完成數據爬取。
如果沒有登錄而直接請求微博的 API 介面,這非常容易導致 403 狀態碼。這個情況我們在 10.2 節也提過。所以在這裏我們實現一個 Middleware,爲每個 Request 新增隨機的 Cookies。
我們先開啓 Cookies 池,使 API 模組正常執行。例如在本地執行 5000 埠,存取:http://localhost:5000/weibo/random 即可獲取隨機的 Cookies,當然也可以將 Cookies 池部署到遠端的伺服器,這樣只需要更改一下存取的鏈接就好了。
那麼在這裏我們將 Cookies 池在本地啓動起來,再實現一個 Middleware 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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,程式碼如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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,修改 settings.py 如下所示:
1 2 3 4 |
DOWNLOADER_MIDDLEWARES = { 'weibo.middlewares.CookiesMiddleware': 554, 'weibo.middlewares.ProxyMiddleware': 555, } |
注意這裏的優先順序設定,前文提到了 Scrapy 的預設 Downloader Middleware 的設定如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ '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 小的數位即可。
到此爲止,整個微博爬蟲就實現完畢了,我們執行如下命令啓動一下爬蟲:
1 |
scrapy crawl weibocn |
類似的輸出結果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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 數據庫檢視數據,爬取下來的數據如圖 13-38 和圖 13-39 所示。
圖 13-38 使用者資訊
圖 13-39 微博資訊
針對使用者資訊,我們不僅爬取了其基本資訊,還把關注和粉絲列表加到了 follows 和 fans 欄位並做了去重操作。針對微博資訊,我們成功進行了時間轉換處理,同時還儲存了微博的圖片列表資訊。
本節程式碼地址:https://github.com/Python3WebSpider/Weibo。
本節實現了新浪微博的使用者及其粉絲關注列表和微博資訊的爬取,還對接了 Cookies 池和代理池來處理反爬蟲。不過現在是針對單機的爬取,後面我們會將此專案修改爲分佈式爬蟲,以進一步提高抓取效率。