使用Scrapy爬取掘金熱門文章的分析和實現

一、分析掘金網頁

1. 獲取瀏覽器URL

直接頁面選擇30內最熱門的文章可得到URL地址爲 https://juejin.im/timeline?sort=monthly_hottest 查看該網頁Dom元素髮現並沒有文章的數據,可得知此爲動態網頁。

2. 獲得數據API

在這裏插入圖片描述在這裏插入圖片描述
由此得到獲取文章的API爲 https://web-api.juejin.im/query

3. 分析請求參數

在登錄狀態下訪問該接口的 Header 中自定義的參數有:

X-Agent: Juejin/Web
X-Legacy-Device-Id: 1575538149621
X-Legacy-Token: eyJhY2Nlc3NfdG9rZWS4iOiJjMHFEbFBnZ1pFMmZtN3NxIiwicmVmcmVzaF90b2tlbiI6IkVoSXJPSlhvTEhRYlRBZmgiLCJ0b2tlbl90eXBlIjoibWFjIiwiZXhwaXJlX2luIjoyNTkyMDAwfDGQ==
X-Legacy-Uid: 5b502c73f265da0f9d19fc58

POST 的參數爲:

{
    "operationName":"",
    "query":"",
    "variables":{
        "tags":[

        ],
        "category":"5562b415e4b00c57d9b94ac8",
        "first":20,
        "after":"",
        "order":"MONTHLY_HOTTEST"
    },
    "extensions":{
        "query":{
            "id":"653b587c5c7c8a00ddf67fc66f989d42"
        }
    }
}

未登陸狀態下的 Header 自定義參數爲:

X-Agent: Juejin/Web
X-Legacy-Device-Id: 
X-Legacy-Token: 
X-Legacy-Uid:

POST 的參數爲:

{
    "operationName":"",
    "query":"",
    "variables":{
        "tags":[

        ],
        "category":"5562b415e4b00c57d9b94ac8",
        "first":20,
        "after":"",
        "order":"MONTHLY_HOTTEST"
    },
    "extensions":{
        "query":{
            "id":"653b587c5c7c8a00ddf67fc66f989d42"
        }
    }
}

從上對比得出Header中 X-Legacy-Device-Id X-Legacy-Token X-Legacy-Uid 不必要,只需要 X-Agent: Juejin/Web 即可。 Post 的參數從中推出

Category: 5562b415e4b00c57d9b94ac8  // 此爲前端分類的標識
Query : id // 頂部搜索條件
order : // 排序方式
First: // 第一頁條數
tags: // Category下的標籤
after: //推測爲滾動條距離底部的距離 分頁相關

返回的數據結構爲:

數據結構
{
	data: {
		articleFeed: {
			items: {
				edges: [] ,
				pageInfo: {
				}
			}
			
		}
	}
}

最終取值應爲 edges[index][nodes]

二、抓取數據

1. 使用scrapy創建項目,項目中 item 根據需求配置 item

## 此處我是用的項目名爲project_002
class Project002Item(scrapy.Item):
    title = scrapy.Field() 
    content = scrapy.Field()
    url = scrapy.Field()
    like = scrapy.Field()
    user = scrapy.Field()
    category = scrapy.Field()
    updated_date = scrapy.Field()
    article_id = scrapy.Field()
    pass

2. 使用命令 scrapy genspider 文件名 網址生成爬蟲文件。

生成後需改造爬蟲文件
添加 Header 參數

headers = {
    "X-Agent": "Juejin/Web",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
    "Content-Type": "application/json",
    "Host": "web-api.juejin.im",
    "Origin": "https://juejin.im"
}

重寫 start_requests 方法,由於是直接爬取前100條,就在 first 直接寫上100,不做分頁處理。

def start_requests(self):
    url = 'https://web-api.juejin.im/query'
    query_data = {"operationName":"","query":"","variables":{"first":100,"after":"","order":"MONTHLY_HOTTEST"},"extensions":{"query":{"id":"21207e9ddb1de777adeaca7a2fb38030"}}}
    response = scrapy.Request(url, method="POST",headers=self.headers, body=json.dumps(query_data),callback=self.parse_item)
    yield response

回調方法處理

def parse_item(self, response):
    item = Project002Item()
    edges = json.loads(response.text)['data']['articleFeed']['items']['edges']
    temp = []
    for edge in edges:
        node = edge['node']
        temp.append({"title": node['title'], "url": node['originalUrl'], "like": node['likeCount'], 'content': node['content'], 'user': node['user']['username'], 'updated_date': node['updatedAt'], 'category': node['category']['name'], 'article_id': node['id']})
    item = temp
    return item

三、儲存到數據庫

將配置文件的 ITEM_PIPELINES 選項打開,在 pipelines 寫入以下代碼(數據庫需要設計相應字段的表):

def __init__(self):
        db = {
            'host': '127.0.0.1',
            'port': 3306,
            'user': 'root',
            'password': 'root',
            'database': 'spiders',
            'charset': 'utf8'
        }
        self.conn = pymysql.connect(**db)
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
        self.cursor.execute("""INSERT IGNORE INTO juejin (id,title,`url`,`like`,content,category,user,updated_date,article_id) 
        VALUES (null,%s,%s,%s,%s,%s,%s,%s,%s)""", 
                    (item['title'], 
                    item['url'], 
                    item['like'], item['content'], item['category'], item['user'], 
                    item['updated_date'],
                    item['article_id']
                    )
                )            
        self.conn.commit()

使用 scrapy crawl 爬蟲名 即可存儲相應數據
在這裏插入圖片描述

總結

掘金的爬蟲相對比較簡單,反爬機制幾乎沒有,非常適合入門練手。
完整代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章