思路分析:
(1)選定起始人(即選擇關注數和粉絲數較多的人--大V)
(2)獲取該大V的個人信息
(3)獲取關注列表用戶信息
(4)獲取粉絲列表用戶信息
(5)重復(2)(3)(4)步實現全知乎用戶爬取
實戰演練:
(1)、創建項目:scrapy startproject zhijutest
(2)、創建爬蟲:cd zhihutest -----scrapy genspider zhihu www.zhihu.com
(3)、選取起始人(這里我選擇了以下用戶)

我們可以看到他關注的人和關注他的人,這些內容是我們(3)(4)步需要獲取的
(3)、更改settings.py

代碼分析:這里我們設置了不遵守robots協議
robots協議:網絡爬蟲協議,它用來告訴用戶那些內容可以爬取,那些內容禁止爬取,一般我們運行爬蟲項目,首先會訪問網站的robots.txt頁面,它告訴爬蟲那些是你可以獲取的內容,這里我們為了方便,即不遵守robots協議。

代碼分析:這里我們設置了User-Agent和authorization字段(這是知乎對請求頭的限制了,即反爬),而這里我們通過設置模擬了在沒有登陸的前提下偽裝成瀏覽器去請求知乎
(4)、頁面初步分析
右擊鼠標打開chrome開發者工具選項,並選中如下箭頭所指,將鼠標放在黃色標記上,我們可以發現右側加載出了一個ajax請求

單擊該ajax請求,得到如下頁面:我們可以看見黃色部分為每位用戶的詳細信息的url,它包含多個參數用來存儲信息

此時再將頁面下滑可以看到如下信息:

該字段為上面參數的字段詳情(Query String Parameters,英文好的小伙伴應該一眼發現)
(5)、更改items.py
承接上面將頁面點擊左側並翻頁,可以看出右側出現了新的Ajax請求:followees:......這就是他關注者信息,通過點擊Preview我們獲取了網頁源代碼,可以發現包含了每一頁的用戶信息,小伙伴們可以核對下,發現信息能匹配上,我們可以從中發現每頁包含20條他的關注者信息,而黑框部分就是包含每一位用戶詳細信息的參數,我們通過它們來定義item.py(即爬什么???)

修改items.py如下:

(6)、更改zhihu.py
第一步:模塊導入
1 # -*- coding: utf-8 -*- 2 import json 3 4 import scrapy 5 6 from ..items import UserItem 7 8 9 class ZhihuSpider(scrapy.Spider): 10 name = 'zhihu' 11 allowed_domains = ['zhihu.com'] 12 start_urls = ['http://zhihu.com/'] 13 14 #設定起始爬取人,這里我們通過觀察發現與url_token字段有關 15 start_user = 'zhouyuan' 16 17 #選取起始爬取人的頁面詳情信息,這里我們傳入了user和include參數方便對不同的用戶進行爬取 18 user_url = 'https://www.zhihu.com/api/v4/members/{user}?include={include}' 19 #用戶詳情參數即包含在include后面的字段 20 user_query = 'allow_message,is_followed,is_following,is_org,is_blocking,employments,answer_count,follower_count,articles_count,gender,badge[?(type=best_answerer)].topics' 21 22 #這是他的關注者的url,這里包含了每位他的關注者的url,同樣我們傳入了user和include參數方便對不同用戶進行爬取 23 follows_url = 'https://www.zhihu.com/api/v4/members/{user}/followees?include={include}&offset={offset}&limit={limit}' 24 #他的每位關注者詳情參數,即包含在include后面的字段 25 follows_query = 'data[*].answer_count,articles_count,gender,follower_count,is_followed,is_following,badge[?(type=best_answerer)].topics' 26 27 #這是他的粉絲的url,這里包含了每位他的關注者的url,同樣我們傳入了user和include參數方便對不同用戶進行爬取 28 followers_url = 'https://www.zhihu.com/api/v4/members/{user}/followees?include={include}&offset={offset}&limit={limit}' 29 #他的每位粉絲的詳情參數,即包含在include后面的字段 30 followers_query = 'data[*].answer_count,articles_count,gender,follower_count,is_followed,is_following,badge[?(type=best_answerer)].topics' 31 32 #重新定義起始爬取點的url 33 def start_requests(self): 34 #這里我們傳入了將選定的大V的詳情頁面的url,並指定了解析函數parseUser 35 yield scrapy.Request(self.user_url.format(user=self.start_user, include=self.user_query), callback=self.parseUser) 36 #這里我們傳入了將選定的大V他的關注者的詳情頁面的url,並指定了解析函數parseFollows 37 yield scrapy.Request(self.follows_url.format(user=self.start_user, include=self.follows_query, offset=0, limit=20), callback=self.parseFollows) 38 #這里我們傳入了將選定的大V的粉絲的詳情頁面的url,並指定了解析函數parseFollowers 39 yield scrapy.Request(self.followers_url.format(user=self.start_user, include=self.followers_query, offset=0, limit=20), callback=self.parseFollowers) 40 41 #爬取每一位用戶詳情的頁面解析函數 42 def parseUser(self, response): 43 #這里頁面上是json字符串類型我們使用json.loads()方法將其變為文本字符串格式 44 result = json.loads(response.text) 45 item = UserItem() 46 47 #這里我們遍歷了items.py中定義的字段並判斷每位用戶的詳情頁中的keys是否包含該字段,如包含則獲取 48 for field in item.fields: 49 if field in result.keys(): 50 item[field] = result.get(field) 51 yield item 52 #定義回調函數,爬取他的關注者與粉絲的詳細信息,實現層層迭代 53 yield scrapy.Request(self.follows_url.format(user=result.get('url_token'), include=self.follows_query, offset=0, limit=20), callback=self.parseFollows) 54 yield scrapy.Request(self.followers_url.format(user=result.get('url_token'), include=self.followers_query, offset=0, limit=20), callback=self.parseFollowers) 55 56 #他的關注者的頁面解析函數 57 def parseFollows(self, response): 58 results = json.loads(response.text) 59 #判斷data標簽下是否含有獲取的文本字段的keys 60 if 'data' in results.keys(): 61 for result in results.get('data'): 62 yield scrapy.Request(self.user_url.format(user=result.get('url_token'), include=self.user_query), callback=self.parseUser) 63 #判斷頁面是否翻到了最后 64 if 'paging' in results.keys() and results.get('paging').get('is_end') == False: 65 next_page = results.get('paging').get('next') 66 yield scrapy.Request(next_page, callback=self.parseFollows) 67 68 #他的粉絲的頁面解析函數 69 def parseFollowers(self, response): 70 results = json.loads(response.text) 71 72 if 'data' in results.keys(): 73 for result in results.get('data'): 74 yield scrapy.Request(self.user_url.format(user=result.get('url_token'), include=self.user_query), callback=self.parseUser) 75 76 if 'paging' in results.keys() and results.get('paging').get('is_end') == False: 77 next_page = results.get('paging').get('next') 78 yield scrapy.Request(next_page, callback=self.parseFollowers)

我們可以看到當我們翻到了最后is_end字段變為了True,而next字段就是下一個頁面的url
(7)、運行下程序,可以看見已經在爬取了

(8)、將結果存入Mongodb數據庫
重寫pipelines.py
1 import pymongo 2 3 class MongoPipeline(object): 4 5 collection_name = 'user' 6 7 def __init__(self, mongo_uri, mongo_db): 8 self.mongo_uri = mongo_uri 9 self.mongo_db = mongo_db 10 11 @classmethod 12 def from_crawler(cls, crawler): 13 return cls( 14 mongo_uri=crawler.settings.get('MONGO_URI'), 15 mongo_db=crawler.settings.get('MONGO_DATABASE') 16 ) 17 18 def open_spider(self, spider): 19 self.client = pymongo.MongoClient(self.mongo_uri) 20 self.db = self.client[self.mongo_db] 21 22 def close_spider(self, spider): 23 self.client.close() 24 25 def process_item(self, item, spider): 26 self.db['user'].update({'url_token' :item['url_token']},{'$set':item},True)
代碼分析:
我們創建了名為user的集合
重寫了__init__方法指定了數據庫的鏈接地址和數據庫名稱
並修改了工廠類函數(具體參見上講ITEM PIPLELIEN用法)
打開數據庫並插入數據並以url_token字段對重復數據執行了更新操作
最后我們關閉了數據庫
再配置下settings.py


再次運行程序,可以看見我們的數據就到了數據庫了

