Scrapy框架的使用之Scrapy爬取新浪微博

前面講解了Scrapy中各個模塊基本使用方法以及代理池、Cookies池。接下來咱們以一個反爬比較強的網站新浪微博爲例,來實現一下Scrapy的大規模爬取。
html

1、本節目標

本次爬取的目標是新浪微博用戶的公開基本信息,如用戶暱稱、頭像、用戶的關注、粉絲列表以及發佈的微博等,這些信息抓取以後保存至MongoDB。git

2、準備工做

請確保前文所講的代理池、Cookies池已經實現並能夠正常運行,安裝Scrapy、PyMongo庫。
github

3、爬取思路

首先咱們要實現用戶的大規模爬取。這裏採用的爬取方式是,以微博的幾個大V爲起始點,爬取他們各自的粉絲和關注列表,而後獲取粉絲和關注列表的粉絲和關注列表,以此類推,這樣下去就能夠實現遞歸爬取。若是一個用戶與其餘用戶有社交網絡上的關聯,那他們的信息就會被爬蟲抓取到,這樣咱們就能夠作到對全部用戶的爬取。經過這種方式,咱們能夠獲得用戶的惟一ID,再根據ID獲取每一個用戶發佈的微博便可。
ajax

4、爬取分析

這裏咱們選取的爬取站點是:https://m.weibo.cn,此站點是微博移動端的站點。打開該站點會跳轉到登陸頁面,這是由於主頁作了登陸限制。不過咱們能夠繞過登陸限制,直接打開某個用戶詳情頁面,例如打開周冬雨的微博,連接爲:https://m.weibo.cn/u/1916655407,便可進入其我的詳情頁面,以下圖所示。
mongodb

咱們在頁面最上方能夠看到周冬雨的關注和粉絲數量。咱們點擊關注,進入到她的關注列表,以下圖所示。數據庫

咱們打開開發者工具,切換到XHR過濾器,一直下拉關注列表,便可看到下方會出現不少Ajax請求,這些請求就是獲取周冬雨的關注列表的Ajax請求,以下圖所示。json

咱們打開第一個Ajax請求,它的連接爲:https://m.weibo.cn/api/container/getIndex?containerid=231051api

-_followers
-_1916655407&luicode=10000011&lfid=1005051916655407&featurecode=20000320&type=uid&value=1916655407&page=2,詳情以下圖所示。

請求類型是GET類型,返回結果是JSON格式,咱們將其展開以後便可看到其關注的用戶的基本信息。接下來咱們只須要構造這個請求的參數。此連接一共有7個參數,以下圖所示。bash

其中最主要的參數就是containeridpage。有了這兩個參數,咱們一樣能夠獲取請求結果。咱們能夠將接口精簡爲:https://m.weibo.cn/api/container/getIndex?containerid=231051服務器

-_followers
-_1916655407&page=2,這裏的 container_id的前半部分是固定的,後半部分是用戶的id。因此這裏參數就能夠構造出來了,只須要修改 container_id最後的 idpage參數便可獲取分頁形式的關注列表信息。

利用一樣的方法,咱們也能夠分析用戶詳情的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}'複製代碼

此處的uidpage分別表明用戶ID和分頁頁碼。

注意,這個API可能隨着時間的變化或者微博的改版而變化,以實測爲準。

咱們從幾個大V開始抓取,抓取他們的粉絲、關注列表、微博信息,而後遞歸抓取他們的粉絲和關注列表的粉絲、關注列表、微博信息,遞歸抓取,最後保存微博用戶的基本信息、關注和粉絲列表、發佈的微博。

咱們選擇MongoDB做存儲的數據庫,能夠更方便地存儲用戶的粉絲和關注列表。

5、新建項目

接下來咱們用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)複製代碼

6、建立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並不必定是徹底對應的。

7、提取數據

咱們開始解析用戶的基本信息,實現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()方法。

  • 提取用戶關注列表內的關鍵信息並生成UserRelationItemid字段直接設置成用戶的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池來防止反爬蟲。

8、數據清洗

有些微博的時間可能不是標準的時間,好比它可能顯示爲剛剛、幾分鐘前、幾小時前、昨天等。這裏咱們須要統一轉化這些時間,實現一個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,咱們便完成了數據清洗工做,這裏主要是時間的轉換。

9、數據存儲

數據清洗完畢以後,咱們就要將數據保存到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/。

10、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狀態碼基本就不會出現。

11、代理池對接

微博還有一個反爬措施就是,檢測到同一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不爲空,也就是說第一次請求失敗以後才啓用代理,由於使用代理後訪問速度會慢一些。因此咱們在這裏設置了只有重試的時候才啓用代理,不然直接請求。這樣就能夠保證在沒有被封禁的狀況下直接爬取,保證了爬取速度。

12、啓用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小的數字便可。

十3、運行

到此爲止,整個微博爬蟲就實現完畢了。咱們運行以下命令啓動爬蟲:

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數據庫查看數據,爬取下來的數據以下圖所示。

針對用戶信息,咱們不只爬取了其基本信息,還把關注和粉絲列表加到了followsfans字段並作了去重操做。針對微博信息,咱們成功進行了時間轉換處理,同時還保存了微博的圖片列表信息。

十4、本節代碼

本節代碼地址爲:https://github.com/Python3WebSpider/Weibo。

十5、結語

本節實現了新浪微博的用戶及其粉絲關注列表和微博信息的爬取,還對接了Cookies池和代理池來處理反爬蟲。不過如今是針對單機的爬取,後面咱們會將此項目修改成分佈式爬蟲,以進一步提升抓取效率。


本資源首發於崔慶才的我的博客靜覓: Python3網絡爬蟲開發實戰教程 | 靜覓

如想了解更多爬蟲資訊,請關注個人我的微信公衆號:進擊的Coder

weixin.qq.com/r/5zsjOyvEZ… (二維碼自動識別)

相關文章
相關標籤/搜索