Python爬蟲入門教程 31-100 36氪(36kr)資料抓取 scrapy
1. 36氪(36kr)資料----寫在前面
今天抓取一個新聞媒體,36kr的文章內容,也是為後面的資料分析做相應的準備的,預計在12月底,爬蟲大概寫到50篇案例的時刻,將會迎來一個新的內容,系統的資料分析博文,記得關注哦~
36kr 讓一部分人先看到未來,而你今天要做的事情確實要抓取它的過去。
2. 36氪(36kr)資料----資料分析
36kr的頁面是一個瀑布流的效果,當你不斷的下拉頁面的時候,資料從後臺追加過來,基於此,基本可以判斷它是ajax非同步的資料,只需要開啟開發者工具,就能快速的定位到想要的資料,我們嘗試一下!
捕獲連結如下
https://36kr.com/api/search-column/mainsite?per_page=20&page=1&_=1543840108547 https://36kr.com/api/search-column/mainsite?per_page=20&page=2&_=1543840108547 https://36kr.com/api/search-column/mainsite?per_page=20&page=3&_=1543840108547 https://36kr.com/api/search-column/mainsite?per_page=20&page=4&_=1543840108547
在多次嘗試之後,發現per_page最大可以擴充套件到300,但是當大於100的資料,返回的資料並不是很理想,所以,我們擬定為100即可,page就是頁碼,這個不斷迴圈疊加即可。
上面的引數還有一個更加重要的值,叫做
total_count
總共有多少文章數目。有這個引數,我們就能快速的拼接出來,想要的頁碼了。
3. 36氪(36kr)資料----建立scrapy專案
scrapy startproject kr36
4. 36氪(36kr)資料----建立爬蟲入口頁面
scrapy genspider Kr36 "www.gaokaopai.com"
5. 36氪(36kr)資料----編寫url生成器
頁面起始地址 start_urls
為第一頁資料,之後會呼叫 parse
函式,在函式內容,我們去獲取 total_count
這個引數
這個地方,需要注意 yield
返回資料為 Request()
關於他的詳細說明,請參照
所有引數清單,引數名字起得好,基本都能代表所有的意思了。比較重要的是 url
和 callback
class scrapy.http.Request(url[, callback, method='GET', headers, body, cookies, meta, encoding='utf-8', priority=0, dont_filter=False, errback])
class Kr36Spider(scrapy.Spider): name = 'Kr36' allowed_domains = ['36kr.com'] start_urls = ['https://36kr.com/api/search-column/mainsite?per_page=100&page=1&_='] def parse(self, response): data = json.loads(response.body_as_unicode()) totle = int(data["data"]["total_count"]) #totle = 201 for page in range(2,int(totle/100)+2): print("正在爬取{}頁".format(page),end="") yield Request("https://36kr.com/api/search-column/mainsite?per_page=100&page={}&_=".format(str(page)), callback=self.parse_item)
6. 36氪(36kr)資料----解析資料
在解析資料過程中,發現有時候資料有缺失的情況發生,所以需要判斷一下 app_views_count
, mobile_views_count
, views_count
, favourite_num
是否出現在字典中。
注意下面程式碼中的Kr36Item類,這個需要提前建立一下
Kr36Item
class Kr36Item(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() app_views_count = scrapy.Field() # APP觀看數量 mobile_views_count = scrapy.Field() # 移動端觀看數量 views_count = scrapy.Field() # PC觀看數量 column_name = scrapy.Field() # 類別 favourite_num = scrapy.Field() # 收藏數量 title = scrapy.Field() # 標題 published_at = scrapy.Field() # 釋出時間 is_free = scrapy.Field() # 是否免費 username = scrapy.Field()
def parse_item(self,response): data = json.loads(response.body_as_unicode()) item = Kr36Item() for one_item in data["data"]["items"]: print(one_item) item["app_views_count"] = one_item["app_views_count"] if "app_views_count" in one_item else 0# APP觀看數量 item["mobile_views_count"] = one_item["mobile_views_count"]if "mobile_views_count" in one_item else 0 # 移動端觀看數量 item["views_count"] = one_item["views_count"]if "views_count" in one_item else 0# PC觀看數量 item["column_name"] = one_item["column_name"]# 類別 item["favourite_num"] = one_item["favourite_num"]if "favourite_num" in one_item else 0# 收藏數量 item["title"] = one_item["title"] # 標題 item["published_at"] = one_item["published_at"]# 釋出時間 item["is_free"] = one_item["is_free"] if "is_free" in one_item else 0# 是否免費 item["username"] = json.loads(one_item["user_info"])["name"] yield item
最後開啟 settings.py
中的 pipelines
編寫資料持久化程式碼
ITEM_PIPELINES = { 'kr36.pipelines.Kr36Pipeline': 300, }
import os import csv class Kr36Pipeline(object): def __init__(self): store_file = os.path.dirname(__file__)+'/spiders/36kr.csv' self.file = open(store_file,"a+",newline="",encoding="utf_8_sig") self.writer = csv.writer(self.file) def process_item(self, item, spider): try: self.writer.writerow(( item["title"], item["app_views_count"], item["mobile_views_count"], item["views_count"], item["column_name"], item["favourite_num"], item["published_at"], item["is_free"], item["username"] )) print("資料儲存完畢") except Exception as e: print(e.args) def close_spider(self,spider): self.file.close()
7. 36氪(36kr)資料----獲取資料
執行上述程式碼,沒有做過多的處理,也沒有調整併發速度,也沒有做反爬措施。跑了一下,大概獲取到了 69936
條資料,和預估的差了300多條,問題不大,原因沒細查,哈哈哈哈