scrapy 基礎教程
1. 認識Scrapy:
來一張圖了解一下scrapy工作流程:(這張圖是在百度下載的)
scrapy 各部分的功能:
1. Scrapy Engine(引擎): 負責Spider,Item Pipeline,Downloader,Scheduler 中間的通訊,信號,數據傳遞等
2. Scheduler(調度器): 負責接收引擎發送過來的 request 請求,並按照一定的方式進行整理隊列,入隊,當引擎需要時,交還給引擎
3. Downloader(下載器): 負責下載 Scrapy Engine(引擎)發送的所有 request 請求,並將其獲取到的 response 交還給 Scrapy Engine(引擎),由 引擎 交給spider 來處理
4. Spider(爬蟲): 它負責處理所有response,從中分析提取數據,獲取item字段需要的數據,並將需要跟進的URL提交個 引擎 再次進入 Scheduler(調度器)
4. Item Pipeline(管道): 它負責處理Spider中獲取到的item,並進行后期處理(詳細分析,過濾,存儲等)的地方
5. Downloader Middlewares(下載中間件): 你可以當作是一個可以自定義擴展下載功能的組件
6. Spider Middlewares(Spider中間件): 可以理解為是一個可以自定義擴展和操作 引擎 和 Spider 之間通信的功能組件(例如進入Spider 的responses 和從 Spider 出去的 requests)
scrapy 運行流程:
1. 引擎: Hi! Spider,你要處理哪一個網站?
2. Spider: 老大要我處理 xxx.xxx.com.
3. 引擎: 你把第一個需要處理的URL給我吧。
4. Spider: 給你,第一個URL是 xxx.xxx.com.
5. 引擎: Hi! 調度器,我這里有request請求你幫我排序入隊一下。
6. 調度器: 好的,正在處理你等一下。
7. 引擎: Hi! 調度器,你把處理好的request請求給我。
8. 調度器: 給你,這是我處理好的request請求。
9. 引擎: Hi! 下載器,你你按照老大的 下載中間件 的設置當我下載一下這個request請求。
10. 下載器: 好的!給你這是下載好的東西。(如果下載失敗:sorry,這個request下載失敗了,然后 引擎 告訴 調度器 ,這個request 下載失敗了,你記錄一下,我們待會再下載)
11. 引擎:Hi! Spider,給你,這是下載好的東西,並且已經按照老大的 下載中間件 處理過了,你自己處理一下(注意!這兒responses默認式交給 def parse() 這個函數處理的)
12. Spider: (處理完畢數據之后對於需要跟進的URL),Hi!引擎,我這里有兩個結果,這個是我需要跟進的URL,還有這個是我獲取到的item數據。
13. 引擎: Hi! 管道 我這里有個item你幫我處理一下!調度器!這是需要跟進的URL你幫我吃力一下。然后從第四步開始循環,知道老大去玩需要的全部數據。
14. 管道 調度器: 好的,現在就做!
注意!只有當調度器中不存在任何request了,整個程序才會停止(也就是說對弈下載失敗的URL,Scrapy也會重新下載)
2. 准備工作:
安裝scrapy
1 pip install wheel 2 pip install scrapy
這里如果安裝失敗(安裝失敗很正常)
https://www.cnblogs.com/xingxingnbsp/p/12132020.html 這里有解決辦法
3. 創建項目:
1 # 創建scrapy項目步驟命令
2 # 創建項目
3 scrapy startproject 項目名 4 # 創建爬蟲
5 scrapy genspider 爬蟲名 www.jinse.com 6 # 運行爬蟲
7 + scrapy crawl 爬蟲名
如果你已經安裝好scrapy 但是還出現下邊錯誤:
問題所在:
這是由於在當前虛擬環境下找不到scrapy
解決問題:
到這里項目就算創建成功了(就是這么簡單O(∩_∩)O哈哈~)
4. scrapy 常用命令:
語法:
scrapy <command> [options] [args]
常用命令:
1 bench Run quick benchmark test 2 check Check spider contracts 3 crawl Run a spider 4 edit Edit spider 5 fetch Fetch a URL using the Scrapy downloader 6 genspider Generate new spider using pre-defined templates 7 list List available spiders 8 parse Parse URL (using its spider) and print the results 9 runspider Run a self-contained spider (without creating a project) 10 settings Get settings values 11 shell Interactive scraping console 12 startproject Create new project 13 version Print Scrapy version 14 view Open URL in browser, as seen by Scrapy
5. 了解項目:
項目目錄
items.py:
數據的存儲容器,在對數據進行有處理的操作時,必須要用,例如寫入txt,插入數據庫等,沒有對數據進行操作時,可以不使用
middlewares.py:
該文件是scrapy的中間件文件,可以設置隨機請求頭,代理,cookie,會話維持等
pipelines.py:
該文件和主要用來存儲數據
settings.py:
該文件是scrapy的設置文件,可以配置數據庫連接等
spiders/jinse.py:
該文件就是我們剛才創建的爬蟲文件
6. 項目開始:
6.1 明確目標:
6.2 分析目標網站:
(1) 網頁右鍵檢查,向下拉:
(2) 發現了三個ajax請求:
(3) 隨便打開一個請求:
(4) 好的找到了數據,我們還要翻頁(這里就要找規律了)
https://api.jinse.com/v6/www/information/list?catelogue_key=news&limit=23&information_id=18886241&flag=down&version=9.9.9&_source=www https://api.jinse.com/v6/www/information/list?catelogue_key=news&limit=23&information_id=18867649&flag=down&version=9.9.9&_source=www https://api.jinse.com/v6/www/information/list?catelogue_key=news&limit=23&information_id=18858401&flag=down&version=9.9.9&_source=www
(5) 把這三個請求地址拿出來很明顯除了 ‘information_id’ 的值不一樣其他的都一樣
(6) 又出來了一個問題 information_id 感覺沒啥規律啊(難搞哦)
(7) 看剛才的請求結果上邊有一個bottom_id 剛好和第二個的 information_id的值一樣(這里我們就不試了,我已經試過了確實是這樣的)
(8) 現在已經知道規律並且知道網址了那就開干吧
6.3 開始寫BUG:
(1) 首先我們先在 items.py 中指定我們要的數據
import scrapy class DemoItem(scrapy.Item): # 文章標題
title = scrapy.Field() # 文章簡介
brief = scrapy.Field() # 文章圖片
image = scrapy.Field()
(2) 指定好我們要的數據 下一步編寫我們的爬蟲 spiders/jinse.py
# -*- coding: utf-8 -*-
import json import scrapy from ..items import DemoItem class JinseSpider(scrapy.Spider): name = 'jinse' allowed_domains = ['www.jinse.com'] start_urls = ['https://api.jinse.com/v6/www/information/list?catelogue_key=news&limit=23&information_id=18851073&flag=down&version=9.9.9&_source=www'] def parse(self, response): # 獲取響應並使用json解析
data = json.loads(response.text) # 獲取下一頁的 bottom_id
bottom_id = data["bottom_id"] # 這里是數據列表
data_list = data["list"] for data in data_list: # 實例化DemoItem
jinse_item = DemoItem() # 獲取文章標題
jinse_item["title"] = data["title"] # 獲取文章簡介
jinse_item["brief"] = data["extra"]["summary"] # 獲取文章圖片
jinse_item["image"] = data["extra"]["thumbnails_pics"][0] # 將數據放入管道中
yield jinse_item # 判斷是否還有下一頁
if bottom_id: # 執行回調函數
yield scrapy.Request( "https://api.jinse.com/v6/www/information/list?catelogue_key=news&limit=23&information_id={}&flag=down&version=9.9.9&_source=www".format(bottom_id), callback=self.parse)
(3) 獲取到了數據我們打印出來看一下 :
scrapy crawl jinse # 注意當前所在的目錄
(4) 結果出來了但是為什么只打印了一頁???(一臉懵逼.....)
(5) 看到錯誤了
這是因為下邊的URL是api接口的地址
(6) 解決問題:
將 api.jinse.com 添加到允許的域名中
(7) 再次運行:
這次沒問題了,程序一頓狂摟(想要停止按 Crlt+c)
6.4 將數據存儲在mysql數據庫中
(1) 創建數據庫(這里我是使用的工具)
1. 創建數據庫 (數據庫名為 jinse)
2. 創建表名叫 jinse
3. 數據庫字段(id要自增,要不然會報錯)
(2) 在 settings.py 中配置數據庫連接參數:
# 配置mysql數據庫連接
mysql_db = { "host":"127.0.0.1", "port":3306, "user":"root", "password":"你的密碼", "db":"jinse" }
(3) 在 pipelines.py 中連接數據庫存儲數據
安裝 pymysql pip install pymysql
from .settings import mysql_db import pymysql class DemoPipeline(object): def __init__(self): host = mysql_db["host"] port = mysql_db["port"] user = mysql_db["user"] password = mysql_db["password"] db = mysql_db["db"] # 創建連接
self.conn = pymysql.connect(host=host, port=port, user=user, password=password, db=db, charset='utf8') # 創建游標
self.cursor = self.conn.cursor() def process_item(self, item, spider): sql = """ insert into jinse(title,brief,image) values ('%s','%s','%s')""" %(item["title"],item["brief"],item["image"]) try: self.cursor.execute(sql) self.conn.commit() except: self.conn.rollback() return item
(4) 在 settings.py 中修改
把注釋去掉
(5) 運行項目
scrapy crawl jinse # 注意當前所在的目錄
跑了10秒左右 505條數據(我的id不是從1開始是因為我之前把數據刪了,速度還可以)