文章采集api(如何通过MySQL存储采集到的数据)
优采云 发布时间: 2022-02-21 06:08文章采集api(如何通过MySQL存储采集到的数据)
MySQL是目前最流行的开源关系数据库管理系统。令人惊讶的是,一个开源项目的竞争力如此之强,以至于它的受欢迎程度不断接近另外两个闭源商业数据库系统:微软的 SQL Server 和甲骨文的甲骨文数据库(MySQL 于 2010 年被甲骨文收购)。)。
它的受欢迎程度不辜负它的名字。对于大多数应用程序,MySQL 是显而易见的选择。它是一个非常灵活、稳定、功能齐全的 DBMS,许多顶级 网站 都在使用它:Youtube、Twitter、Facebook 等。
由于使用广泛、免费、开箱即用,是web data采集项目中常用的数据库,在此文章我们介绍如何存储数据采集 通过 MySQL。
安装 MySQL
如果您是 MySQL 新手,您可能会觉得它有点麻烦。其实安装方法和安装其他软件一样简单。归根结底,MySQL 是由一系列数据文件组成的,存储在你的远程服务器或本地计算机上,其中收录了存储在数据库中的所有信息。
在Windows上安装MySQL,在Ubuntu上安装MySQL,在MAC上安装MySQL具体步骤在这里:在所有平台上安装MySQL
此处无需过多解释,按照视频操作即可。
基本命令
MySQL服务器启动后,与数据库服务器交互的方式有很多种。因为许多工具都是图形界面,所以您可以不使用 MySQL 的命令行(或很少使用)来管理数据库。phpMyAdmin 和 MySQL Workbench 等工具可以轻松查看、排序和创建数据库。但是,掌握命令行操作数据库还是很重要的。
除了用户定义的变量名,MySQL 不区分大小写。例如,SELECT 与 select 相同,但习惯上所有 MySQL 关键词 的 MySQL 语句都以大写形式编写。大多数开发人员还喜欢使用小写字母作为数据库和数据表名称。
首次登录 MySQL 数据库时,没有数据库来存储数据。我们需要创建一个数据库:
CREATE DATABASE scraping_article DEFAULT CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI;
因为每个 MySQL 实例可以有多个数据库,所以在使用数据库之前需要指定数据库名称:
使用scraping_article
从现在开始(直到关闭 MySQL 链接或切换到另一个数据库),所有命令都在这个新的“scraping_article”数据库中运行。
所有的操作看起来都很简单。那么在数据库中新建表的操作方法应该也差不多吧?我们在库中新建一个表来存储采集的网页文章的数据:
创建表文章;
结果显示错误:
错误 1113 (42000): 一个表必须至少有 1 列
与数据库不同,MySQL 数据表必须有列,否则无法创建。要在 MySQL 中定义字段(数据列),我们还必须将字段定义放在 CREATE TABLE 语句之后的带括号的逗号分隔列表中:
create table articles
(
id int auto_increment
primary key,
title varchar(64) null,
body text null,
summary varchar(256) null,
body_html text null,
create_time datetime default CURRENT_TIMESTAMP null,
time_updated datetime null,
link_text varchar(128) null
);
每个字段定义由三部分组成:
在字段定义列表的最后,还定义了一个“主键”(key)。MySQL使用这个主键来组织表的内容,方便以后快速查询。以后文章会介绍如何通过这些主键来提高数据库的查询速度,不过目前我们可以使用表的id列作为主键。
语句执行完毕后,我们可以使用DESCRIBE查看数据表的结构:
+--------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(64) | YES | | NULL | |
| body | text | YES | | NULL | |
| summary | varchar(256) | YES | | NULL | |
| body_html | text | YES | | NULL | |
| create_time | datetime | YES | | CURRENT_TIMESTAMP | |
| time_updated | datetime | YES | | NULL | |
| link_text | varchar(128) | YES | | NULL | |
+--------------+--------------+------+-----+-------------------+----------------+
8 rows in set (0.03 sec)
现在这张表是空表,我们插入数据看看,如下图:
INSERT INTO articles(title,body,summary,body_html,link_text) VALUES ("Test page title","Test page body.","Test page summary.","<p>Test page body.","test-page");</p>
这里需要注意,虽然articles表有8个字段(id、title、body、summary、body_html、create_time、time_update、link_text),但实际上我们只插入了5个字段(title、body、summary、body_html、link_text) ) ) 数据。因为id字段是自动递增的(MySQL每次插入数据时默认递增1),一般不需要处理。另外create_time字段的类型是current_timestamp,时间戳是通过插入的默认。
当然,我们也可以自定义字段内容来插入数据:
INSERT INTO articles(id,title,body,summary,body_html,create_time,link_text) VALUES (4,"Test page title","Test page body.","Test page summary.","<p>Test page body.","2021-11-20 15:51:45","test-page");</p>
只要你定义的整数不在数据表的id字段中,就可以插入到数据表中。但是,这非常糟糕;除非绝对必要(比如程序中缺少一行数据),否则让 MySQL 自己处理 id 和 timestamp 字段。
现在表中有一些数据,我们可以通过多种方式查询这些数据。以下是 SELECT 语句的一些示例:
SELECT * FROM articles WHERE id=1;
该语句告诉 MySQL “从文章表中选择 id 等于 2 的所有数据”。此星号 (*) 是通配符,表示所有字段。这行语句将显示所有满足条件的字段(其中 id=1))。如果没有 id 等于 1 的行,它将返回一个空集。例如,以下不区分大小写的查询将返回标题字段中收录“test”的所有行的所有字段(% 符号表示 MySQL 字符串通配符):
SELECT * FROM articles WHERE title LIKE "%test%";
但是如果你有很多字段并且你只想返回其中的一部分呢?您可以使用以下命令代替星号:
SELECT title, body FROM articles WHERE body LIKE "%test%";
这将只返回正文内容收录“test”的所有行的标题和正文字段。
DELETE 语句的语法类似于 SELECT 语句:
DELETE FROM articles WHERE id=1;
由于数据库的数据删除无法恢复,建议在执行DELETE语句前使用SELECT确认要删除的数据(上述删除语句可以使用SELECT * FROM文章WHERE id=1;查看),以及然后将 SELECT * 替换为 DELETE 就可以了,这是一个好习惯。很多程序员都有过 DELETE 误操作的悲惨故事,也有一些恐怖的故事是有人惊慌失措的忘记在语句中输入 WHERE,结果所有*敏*感*词*都被删除了。不要让这种事情发生在你身上!
要介绍的另一件事是 UPDATE 语句:
UPDATE articles SET title="A new title", body="Some new body." WHERE id=4;
以上只使用了最基本的 MySQL 语句来做一些简单的数据查询、创建和更新。
与 Python 集成
Python 没有对 MySQL 的内置支持。但是,有很多开源的可以用来和 MySQL 交互,Python 2.x 和 Python 3.x 版本都支持。最著名的一个是 PyMySQL。
我们可以使用pip来安装,执行如下命令:
python3 -m pip 安装 PyMySQL
安装完成后,我们就可以使用 PyMySQL 包了。如果您的 MySQL 服务器正在运行,您应该能够成功执行以下命令:
import pymysql
import os
from dotenv import load_dotenv
class DataSaveToMySQL(object):
def __init__(self):
# loading env config file
dotenv_path = os.path.join(os.getcwd(), '.env')
if os.path.exists(dotenv_path):
load_dotenv(dotenv_path)
conn = pymysql.connect(host=os.environ.get('MYSQL_HOST'), port=os.environ.get('MYSQL_PORT'),
user=os.environ.get('MYSQL_USER'), password=os.environ.get('MYSQL_PASSWORD'),
db=os.environ.get('MYSQL_DATABASES'))
cur = conn.cursor()
cur.execute("SELECT * FROM articles WHERE id=4;")
print(cur.fetchone())
cur.close()
conn.close()
这个程序有两个对象:一个连接对象(conn)和一个游标对象(cur)。
连接/游标模式是数据库编程中常用的模式。当您不熟悉数据库时,有时很难区分这两种模式之间的区别。连接方式除了连接数据库外,还发送数据库信息,处理回滚操作(当一个查询或一组查询中断时,数据库需要回到初始状态,一般使用事务来实现状态回滚),创建新游标等
一个连接可以有很多游标,一个游标跟踪一种状态信息,比如跟踪数据库的使用状态。如果您有多个数据库,并且需要写入所有数据库,则需要多个游标来处理。游标还可以收录上次查询执行的结果。查询结果可以通过调用cur.fetchone()等游标函数获得。
请记住在使用完连接和游标后关闭它们。如果不关闭,会导致连接泄漏(connection leak),造成连接关闭现象,即连接不再使用,但是数据库无法关闭,因为数据库不确定是否你想继续使用它。这种现象会一直消耗数据库资源,所以使用数据库后记得关闭连接!
刚开始时,您要做的就是将 采集 的数据保存到数据库中。我们继续采集blog文章的例子来演示如何实现数据存储。
import pymysql
import os
from dotenv import load_dotenv
from config import logger_config
from utils import connection_util
class DataSaveToMySQL(object):
def __init__(self):
# loading env config file
dotenv_path = os.path.join(os.getcwd(), '.env')
if os.path.exists(dotenv_path):
load_dotenv(dotenv_path)
# MySQL config
self._host = os.environ.get('MYSQL_HOST')
self._port = int(os.environ.get('MYSQL_PORT'))
self._user = os.environ.get('MYSQL_USER')
self._password = os.environ.get('MYSQL_PASSWORD')
self._db = os.environ.get('MYSQL_DATABASES')
self._target_url = 'https://www.scrapingbee.com/blog/'
self._baseUrl = 'https://www.scrapingbee.com'
self._init_connection = connection_util.ProcessConnection()
logging_name = 'store_mysql'
init_logging = logger_config.LoggingConfig()
self._logging = init_logging.init_logging(logging_name)
def scrape_data(self):
get_content = self._init_connection.init_connection(self._target_url)
if get_content:
parent = get_content.findAll("section", {"class": "section-sm"})[0]
get_row = parent.findAll("div", {"class": "col-lg-12 mb-5 mb-lg-0"})[0]
get_child_item = get_row.findAll("div", {"class": "col-md-4 mb-4"})
for item in get_child_item:
# 获取标题文字
get_title = item.find("a", {"class": "h5 d-block mb-3 post-title"}).get_text()
# 获取发布时间
get_release_date = item.find("div", {"class": "mb-3 mt-2"}).findAll("span")[1].get_text()
# 获取文章描述
get_description = item.find("p", {"class": "card-text post-description"}).get_text()
self.article_save_mysql(title=get_title, description=get_description, release_date=get_release_date)
else:
self._logging.warning('未获取到文章任何内容,请检查!')
def article_save_mysql(self, title, description, release_date):
connection = pymysql.connect(host=self._host, port=self._port, user=self._user, password=self._password,
db=self._db, charset='utf-8')
with connection.cursor() as cursor:
# Create a new record
sql = "INSERT INTO articles (title,summary,create_time) VALUES (%s,%s,%s);"
cursor.execute(sql, (title, description, release_date))
# connection is not autocommit by default. So you must commit to save
# your changes.
connection.commit()
这里需要注意几点:首先,将 charset='utf-8' 添加到连接字符串中。这是为了让conn把所有发送到数据库的信息都当作utf-8编码格式(当然前提是数据库默认编码设置为UTF-8)。
然后需要注意article_save_mysql函数。它有3个参数:title、description和release_date,并将这两个参数添加到INSERT语句中并用游标执行,然后用游标确认。这是将光标与连接分开的一个很好的例子;当游标存储一些数据库和数据库上下文信息时,需要通过连接确认才能将信息传递到数据库中,然后再将信息插入到数据库中。
上述代码没有使用 try...finally 语句关闭数据库,而是使用 with() 关闭数据库连接。在上一期中,我们也使用了 with() 来关闭 CSV 文件。
PyMySQL的规模虽然不大,但里面有一些非常实用的功能,在本文章中就不演示了。具体请参考 Python DBAPI 标准文档。
以上是关于将采集的内容保存到MySQL。本示例的所有代码都托管在 github 上。
github: