在上一篇文章中,我们讲解了爬虫如何存储CSV文件。在本文中,我们将解释如何将收集到的数据保存到MySQL数据库中。MySQL是目前最流行的开源关系型数据库管理系统。令人惊讶的是,一个开源项目竟能如此具有竞争力,其受欢迎程度已接近两个闭源商业数据库系统:微软的SQLServer和甲骨文的OracleDatabase(MySQL于2010年被甲骨文收购)。).它的受欢迎程度不辜负它的名字。对于大多数应用程序,MySQL是显而易见的选择。它是一个非常灵活、稳定、功能齐全的DBMS,被许多顶级网站使用:Youtube、Twitter和Facebook等。因为它使用广泛、免费、开箱即用,所以它是一个常用的数据库在网络数据收集项目中。在本文中,我们将介绍如何通过MySQL存储收集到的数据。安装MySQL如果您是MySQL的新手,您可能会觉得它有点麻烦。其实安装方法和安装其他软件一样简单。归根结底,MySQL是由一系列数据文件组成的,存储在你的远程服务器或本地计算机上,其中包含了数据库中存储的所有信息。Windows安装MySQL,Ubuntu安装MySQL,MAC安装MySQL。具体步骤在这里:在所有平台上安装MySQL这里就不做说明了,跟着视频操作就可以了。基本命令MySQL服务器启动后,可以通过多种方式与数据库服务器进行交互。因为很多工具都是图形界面,所以不用MySQL的命令行(或者很少用到命令行)也可以管理数据库。phpMyAdmin和MySQLWorkbench等工具可以轻松查看、排序和创建数据库。但是掌握命令行操作数据库还是很重要的。除了用户定义的变量名,MySQL不区分大小写。例如,SELECT与select相同,但在编写MySQL语句时习惯将MySQL关键字全部大写。大多数开发人员还喜欢使用小写字母作为数据库和数据表名称。第一次登录MySQL数据库时,没有数据库可以存储数据。我们需要创建一个数据库:CREATEDATABASEscraping_articleDEFAULTCHARACTERSETUTF8COLLATEUTF8_GENERAL_CI;因为每个MySQL实例可以有多个数据库,所以在使用一个数据库之前需要指定数据库的名称:USEscraping_article从现在开始(直到关闭MySQL链接或切换到另一个数据库之前),所有命令都在这个新的“scraping_article”数据库。所有的操作看起来都很简单。那么在数据库中新建表的操作方法应该类似吧?我们在库中新建一张表,用来存放收集到的网页文章数据:CREATETABLEarticles;结果显示错误:ERROR1113(42000):Atablemusthaveatleast1column与数据库不同,MySQL数据表必须有1列,否则无法创建。为了在MySQL中定义字段(数据列),我们还必须在CREATETABLE语句之后将字段定义放入带括号、逗号分隔的列表中:createtablearticles(idintauto_incrementprimarykey,titlevarchar(64)null,bodytextnull,summaryvarchar(256)null,body_htmltextnull,create_timedatetimedefaultCURRENT_TIMESTAMPnull,time_updateddatetimenull,link_textvarchar(128)null);每个字段定义由三部分组成:名称(id、标题、正文等)数据类型(INT、VARCHAR、TEXT)其他可选属性(NOTNULLAUTO_INCREMENT)在字段定义列表的末尾,还定义了一个“primary钥匙”(钥匙)。MySQL使用这个主键来组织表的内容,以便以后快速查询。在以后的文章中,我会介绍如何使用这些主键来提高数据库的查询速度,但是目前,我们可以使用表的id列作为主键。语句执行后,我们可以使用DESCRIBE查看数据表的结构:+------------+------------+------+-----+--------------------+----------------+|领域|类型|空|键|默认|额外|+------------+------------+------+-----+--------------------+----------------+|编号|整数(11)|否|优先级|空|自动递增||标题|变种(64)|是||空|||身体|文字|是||空|||总结|变种(256)|是||空|||正文_html|||空|||创建时间|日期时间|是||当前_时间戳|||更新时间|日期时间|是||空|||链接文本|变种(128)|------+----------------+------+-----+-----------------+-------------+8组中的行(0.03sec)现在这个表是一个空表,我们来插入数据,如下图:页面摘要。","测试页面正文。
","test-page");这里需要注意,虽然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,默认插入时间戳。当然我们也可以自定义字段内容插入数据:INSERTINTOarticles(id,title,body,summary,body_html,create_time,link_text)VALUES(4,"测试页标题","测试页正文","测试页摘要。","测试页正文。
","2021-11-2015:51:45","test-page");只要你定义的整数不在数据表的id字段中,他就可以插入到数据表中。但是,这很糟糕;除非绝对必要(比如程序中遗漏了一行数据),让MySQL自己处理id和timestamp字段。现在表中有了一些数据,我们可以通过多种方式查询数据。下面是一些SELECT语句的例子:SELECT*FROMarticlesWHEREid=1;这个语句告诉MySQL,“从articles表中选择所有id等于2的数据。”星号(*)是通配符,代表所有字段,这行语句会显示所有满足条件(其中id=1)的字段的内容。如果没有id等于1的行,则返回一个空集。例如,以下不区分大小写的查询返回标题字段中包含“test”的所有行中的所有字段(%符号表示MySQL字符串通配符):SELECT*FROMarticlesWHEREtitleLIKE"%test%";但是如果你有很多字段并且你只想返回其中的一些怎么办?您可以使用以下方法代替星号:SELECTtitle,bodyFROMarticlesWHEREbodyLIKE"%test%";这将只返回正文内容包含"test"的所有行的标题和正文字段。DELETE语句的语法类似于SELECT语句的语法:DELETEFROMarticlesWHEREid=1;由于数据库中的数据删除无法恢复,建议在执行DELETE语句之前先用SELECT确认要删除的数据(上面的删除语句可以用SELECT*FROMarticlesWHEREid=1;查看),以及然后只需将SELECT*替换为DELETE,这将是一个好习惯。许多程序员都有关于DELETE被误用的悲惨故事,以及人们在恐慌中忘记在语句中放置WHERE并删除了所有客户数据的恐怖故事。不要让这种事发生在你身上!另外需要介绍的是UPDATE语句:UPDATEarticlesSETtitle="Anewtitle",body="Somenewbody."其中id=4;以上只是用最基本的MySQL语句做一些简单的数据查询,创建和更新作业。与Python集成Python没有对MySQL的内置支持。但是,有很多开源程序可以用来与MySQL交互,Python2.x和Python3.x都支持。最著名的是PyMySQL。我们可以使用pip来安装,执行如下命令:python3-mpipinstallPyMySQL安装完成后,我们就可以使用PyMySQL包了。如果您的MySQL服务器正在运行,您应该能够成功执行以下命令:getcwd(),'.env')ifos.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*FROMarticlesWHEREid=4;")print(cur.fetchone())cur.close()conn.close()这个程序有两个对象:连接对象(conn)和游标对象(当前)。连接/游标模式是数据库编程中常用的模式。刚接触数据库的时候,有时很难区分这两种模式的区别。连接方式除了连接数据库外,还会发送数据库信息,处理回滚操作(当一个查询或一组查询中断时,数据库需要回到初始状态,一般使用事务来实现状态回滚),并创建新的游标等等。一个连接可以有很多游标,一个游标跟踪一个状态(state)信息,比如跟踪一个数据库的使用状态。如果有多个数据库,需要向所有数据库写入内容,就需要多个游标来处理。游标还可以包含上次查询执行的结果。通过调用游标函数,如cur.fetchone(),可以得到查询结果。永远记得在完成连接和游标后关闭它们。如果不关闭,会造成连接泄漏(connectionleak),导致关闭连接的现象,即连接不再使用,但是数据库无法关闭,因为数据库不确定是否你想继续使用它。这种现象会一直消耗数据库资源,所以用完数据库记得关闭连接!一开始,您要做的就是将收集到的数据保存到数据库中。我们继续收集博文示例来演示如何实现数据存储。importpymysqlimportosfromdotenvimportload_dotenvfromconfigimportlogger_configfromutilsimportconnection_utilclassDataSaveToMySQL(object):def__init__(self):#loadingenvconfigfiledotenv_path=os.path.join(os.getcwd(),'.env')ifos.path.exists(dotenv_path):load_dotenv(dotenv_path)#MySQL配置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)defscrape_data(self):get_content=self._init_connection.init_connection(self._target_url)如果get_content:parent=get_content.findAll("section",{"class":"section-sm"})[0]get_row=parent.findAll("div",{"class":"col-lg-12mb-5mb-lg-0"})[0]get_child_item=get_row.findAll("div",{"class":"col-md-4mb-4"})foriteminget_child_item:#获取标题文本get_title=item.find("a",{"class":"h5d-blockmb-3post-title"}).get_text()#获取发布日期get_release_date=item.find("div",{"class":"mb-3mt-2"}).findAll("span")[1].get_text()#获取文章描述get_description=item.find("p",{"class":"card-textpost-description"}).get_text()self.article_save_mysql(title=get_title,description=get_description,release_date=get_release_date)else:self._logging.warning('没有得到文章的任何内容,请查收!')defarticle_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,字符集='utf-8')withconnection.cursor()ascursor:#Createanewrecordsql="INSERTINTOarticles(title,summary,create_time)VALUES(%s,%s,%s);"cursor.execute(sql,(title,description,release_date))#默认情况下连接不是自动提交的。所以你必须承诺保存#你的更改。connection.commit()这里有几点需要注意:首先,在连接字符串中要加上charset='utf-8',这是为了让conn把所有发送到数据库的信息都当作utf-8编码格式(当然前提是数据库默认编码设置为UTF-8)。然后需要注意的是article_save_mysql函数。它有3个参数:title、description和release_date,这两个参数加在一条INSERT语句中游标执行,然后游标确认。这是将游标与连接分开的一个很好的例子;当游标存储一些数据库和数据库上下文(context)信息时,它需要通过连接确认将这些信息传递到数据库中,然后再将这些信息插入到数据库中。上面的代码并没有使用try...finally语句来关闭数据库,而是使用with()来关闭数据库连接。在上一期中,我们也使用了with()来关闭CSV文件。PyMySQL虽然规模不大,但是里面有一些非常实用的功能,本文就不一一展示了。具体请参考PythonDBAPI标准文档。以上是将采集到的内容保存到MySQL中。这个例子的所有代码都托管在github上。github:https://github.com/sycct/Scra...如有任何问题,欢迎在github上issue。