思路分析:ajax
(1)選定起始人(即選擇關注數和粉絲數較多的人--大V)chrome
(2)獲取該大V的我的信息數據庫
(3)獲取關注列表用戶信息json
(4)獲取粉絲列表用戶信息api
(5)重複(2)(3)(4)步實現全知乎用戶爬取瀏覽器
實戰演練:網絡
(1)、建立項目:scrapy startproject zhijutestdom
(2)、建立爬蟲:cd zhihutest -----scrapy genspider zhihu www.zhihu.comscrapy
(3)、選取起始人(這裏我選擇瞭如下用戶)ide
咱們能夠看到他關注的人和關注他的人,這些內容是咱們(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
再次運行程序,能夠看見咱們的數據就到了數據庫了