前面的一至八篇我們一直在研究如何從網(wǎng)站上快速、方便的獲取數(shù)據(jù),并將獲取到的數(shù)據(jù)存儲在數(shù)據(jù)庫中。但是將數(shù)據(jù)存儲在數(shù)據(jù)中并不是我們的目的,獲取和存儲數(shù)據(jù)的目的是為了更好的利用這些數(shù)據(jù),利用這些數(shù)據(jù)的前提首先需要從數(shù)據(jù)庫按一定的格式來讀取數(shù)據(jù),這一篇主要介紹如何實現(xiàn)通過 RESTful API 來獲取數(shù)據(jù)庫中的數(shù)據(jù)。
好吧,廢話有點多,到此介紹吧,接來下進入技術(shù)細節(jié)。
RESTful 是一種軟件架構(gòu)風格、設(shè)計風格,而不是標準,只是提供了一組設(shè)計原則和約束條件。它主要用于客戶端和服務(wù)器交互類的軟件。基于這個風格設(shè)計的軟件可以更簡潔,更有層次,更易于實現(xiàn)緩存等機制。
匹配REST設(shè)計風格的Web API稱為RESTful API。它從三個方面資源進行定義。第一,直觀簡短的資源地址:URI;第二,傳輸?shù)馁Y源:Web服務(wù)接受與返回的互聯(lián)網(wǎng)媒體類型,比如:JSON,XML,YAML等;第三,對資源的操作:Web服務(wù)在該資源上所支持的一系列請求方法(比如:POST,GET,PUT或DELETE)。
實現(xiàn) RESTful API 需要先實現(xiàn)一個 web 服務(wù)器,在本篇中我們通過已有的框架 Flask 來實現(xiàn) web 服務(wù)器,然后在 Flask 的基礎(chǔ)上連通數(shù)據(jù)庫,實現(xiàn) RESTful API 的訪問。
至于 Flask 框架在這里就不做介紹了「其實是我自己也不太懂」,但是你可以在這里 https://dormousehole.readthedocs.io/en/latest/index.html 獲取更多信息。
建立 Flask 基礎(chǔ)服務(wù)
Flask 是一個輕量級的 Web 應(yīng)用框架。通過 Flask 來實現(xiàn)一個 Web 服務(wù)非常簡單,簡單到只需要五行代碼。
from flask import Flask
app = Flask(__name__)
@app.routr('/')
def hello_world():
return 'Hello World!'
上面使用 Flask 的一個最簡單的示例,我們的示例沒有這么簡單,但是也差不多:)。在這個示例中我們需要創(chuàng)建一個 Flask 的實例、初始化數(shù)據(jù)庫控制和 API 控制框架。代碼如下:
from flask import Flask
import logging
from .module import (
db,
api,
)
logger = logging.getLogger(__name__)
def create_app(config=None):
app = Flask(
'pycrawler', instance_relative_config=True
)
config_app(app, config)
configure_module(app)
return app
def config_app(app, config):
app.config.from_object("pycrawler.configs.default.DefaultConfig")
def configure_module(app):
# initialization database
db.init_app(app)
api.init_app(app)
在程序中通過 app.config.from_object 從配置文件中讀取相關(guān)的配置內(nèi)容,在配置文件中完成數(shù)據(jù)及 flask 的配置。
數(shù)據(jù)庫初始化及數(shù)據(jù)類型的實現(xiàn)
我們使用 Flask 的擴展 Flask-sqlalchemy 來實現(xiàn)數(shù)據(jù)的操作。
Flask-SQLAlchemy 是一個為您的 Flask 應(yīng)用增加 SQLAlchemy 支持的擴展,它致力于簡化在 Flask 中 SQLAlchemy 的使用,提供了有用的默認值和額外的助手來更簡單地完成常見任務(wù)。
flask_sqlalchemy 的使用非常的簡單,僅僅需要簡單的初始化,然后在配置文件加入數(shù)據(jù)庫的 URI 配置即可實現(xiàn)數(shù)據(jù)庫的 CRUD。在這個示例中我們在兩個地方對 flask_sqlalchemy 進行初始化。
首先是初始化 SQLAlchemy 本身,初始化代碼如下:
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
from flask_restful import Api
metadata = MetaData(
naming_convention={
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s",
}
)
db = SQLAlchemy(metadata=metadata)
其次是將 flask 的實例傳入給 flask_sqlchemy。代碼如下:
# initialization database
db.init_app(app)
最后在配置文件中增加 SQLAlchemy 的配置選項。
#Database
# For SQLite:
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + basedir + '/' + \
'prcrawler-web.sqlite'
# This option will be removed as soon as Flask-SQLAlchemy removes it.
# At the moment it is just used to suppress the super annoying warning
SQLALCHEMY_TRACK_MODIFICATIONS = False
# This will print all SQL statements
SQLALCHEMY_ECHO = False
做完上面的工作以后,數(shù)據(jù)庫已經(jīng)可以正常的工作起來,可以開始著手實現(xiàn)數(shù)據(jù)模型,我們需要連接到前面爬蟲存儲數(shù)據(jù)的數(shù)據(jù)庫,因此需要維持兩個數(shù)據(jù)模型的一致,這里就不再貼出數(shù)據(jù)模型的代碼了。
RESTful API 的實現(xiàn)
在這里使用 flask-restful 擴展來實現(xiàn) RESTful API。flask-restful 的初始同 flask-sqlalchemy 的初始化方法相同。
#創(chuàng)建 api 的實例
api = Api()
#向 api 實例傳入 flask 實例
api.init_app(app)
flask-restful 初始完成后,即可建立 api 的類,以獲取一個元件的信息為例來介紹 api 的建立過程。
from flask_restful import Resource, reqparse
from sqlalchemy import func
from pycrawler.module import db, api
from pycrawler.material.models import Brands, Materials, Price
from flask import jsonify
class CrawlerApi(Resource):
def get(self, id):
material = db.session.query(Materials).filter(Materials.id==id).first()
if material is not None:
return material.to_json()
return '', 404
api.add_resource(CrawlerApi, '/api/v0.1/crawler/material/<int:id>')
在 add_resource 中我們設(shè)置 API 的路徑為 /api/v0.1/crawler/material/id 可以通過該 API 來獲取固定 id 的元件的信息。在類 CrawlerApi 中我們實現(xiàn)了一個 get 函數(shù),該函正如其名對應(yīng)了 http 的 get 方法,除了 get 方法我們還能夠以相同的方法來實現(xiàn) post、put、patch、delete 等方法。在 get 函數(shù)中,通過傳入的 id 編號,從數(shù)據(jù)庫中讀出該元件的完整信息,并轉(zhuǎn)換為 json 數(shù)據(jù)返回給客戶端,當 id 不存在是將返回一個 404 錯誤。
在 add_resource 中 <int:id> 將 id 設(shè)置為一個整數(shù),在 get 函數(shù)中傳入的 id 參數(shù)即為一個整數(shù),當然我們也可以設(shè)置為字符串類型。
完成以上代碼后,我們可以通過以下命令來獲取 id 為 100 的元件的信息。
curl http://127.0.0.1:5000/api/v0.1/crawler/material/100
完整的代碼可以通過 api 來訪問所有的元件信息、生產(chǎn)商信息,并可以查看同一個生產(chǎn)商所生產(chǎn)的所有元件。完整的代碼可以在 github 上查看。