python数据入库_python爬虫(中)--数据建模与保存(入库)

前言

前面,讲的是提取出来的数据保存进一个extracted_data,再保存进extracted_data_,变成一个list包含list的情况,当然你只提取一项,那就没有必要这么做了,可是我的项目中要求可能要提取十几二十项,我为了后面入库方便,所以前面做了这么一个工作。

到提取为止,基本爬虫差不多就完成了,什么是基本爬虫,基本爬虫=请求+提取+保存,而不考虑一些针对反反爬的策略制定等情况。现在我们请求函数有了,提取函数有了,现在就差一个保存函数了。我们这里选择的是保存到MySQL数据库中,当然你也可以保存成为.html等格式的文本,我们保存成数据库是为了后面方便使用考虑.不过在保存之前请认真考虑一下你的数据建模问题.

数据建模不是单独存在的,更多的是为了入库而准备的,根据自己需要的数据有多少种类和每种数据的特征,甚至还要考虑到大数据量存储的问题和未来要提数据的场景,来设计数据库中的表,这里工作很多,很考验数据结构的基本功,换言之是一个很费脑,而且要发挥想象力的步骤,所以做这一步的时候最好不要在昏昏欲睡的时候做,要在头脑清晰最为适宜.

保存到文件

简单提提文件保存,先上个保存成HTML文件为例子:

#! /usr/bin/env python

#encoding:utf-8

from os import makedirs

from os.path import exists

import codecs

import json

def save_As_HTMLFile(directory,extracted_data_):

if isinstance(extracted_data_,list) :

print 'the sourceCode you put in save_As_HTMLFile() is a list!!Here will transform list into stringn'

#json用在列表/字典的转unicode上

extracted_data_=json.dumps(extracted_data_,encoding="utf-8",ensure_ascii=False)

if not exists(directory):

makedirs(directory)

print 'Finish Making Directory ',directory

filename=directory+'extracted_data_from_phantomjs.html'

f=codecs.open(filename,'wb')#wb是以二进制写模式打开(打开前文件会被清空)更多的看下面注意第四点

print 'saving data...n'

f.write(extracted_data_)#write()里面要放的是str/buffer,不能是JPEG或者其他奇奇怪怪的东西

print 'Saved.n'

f.close()

return

要注意一下几点:

if isinstance(extracted_data_,list)这里是为了应付之前extracted_data_传进来是list的情况,如果这个if判断到传进来的extracted_data_那么就返回True,然后用json模块中的json.dumps()的方法直接转换成字符串格式,unicode编码的文本~

codecs模块的应用,知道python的朋友应该知道其实不用codecs这个模块,把 f=codecs.open(filename,’wb’)换成f=open(filename,’wb’)也是一样的效果,那么为什么要用codecs.open的方法呢?

答:先来讲讲历史,最早的时候只有open(),可是你也知道python2的编码问题是有多么蛋疼(所以学习python得善用type()方法),所以就有了codecs.open()。而io.open(),其实是因为python2的open()是由File模块提供的,而python3的open()是由io模块提供的。然后,python2.6引入python3的特性,叫io.open(),以区别于原来由File模块提供的open()。python3建议直接用open(),而python2.*用codecs.open()特别是有中文的情况下,如果希望代码能同时是兼容python2和3,就直接用codecs.open(),这就是为什么我们在上面代码里面用codecs.open()的原因,主要考虑compatible的问题。

codecs.open()和open()[指io.open()]使用上的区别?

Answer : io.open() doesn’t always produce unicode strings,if you pass ‘rb’ as the mode,the file is opened in a binary mode,not text mode,and read() method will return bytes.

codecs.open() always open the file in binary mode.

open(),io.open()还是codecs.open()中模式名称用法是一样的,都可以直接参考open()参数mode那一项的设置——详细请见博客

P.s.既然讲到了python的文件保存,那就顺便说说python中获取用户输入的方法——raw_input()和input():

raw_input():任何都可以输入,无论输入什么都会当成字符串

input() : 希望用户的输入的是一个合法python表达式,比如你输入字符串时必须使用引号(单双引号都可以)引起来,不然就报SyntaxError

本质上input()还是调用的是raw_input()实现的,只是调用完raw_input()后再调用eval()

※除非是对input()有需求,不然一般情况推荐raw_input()

mysql">保存到MySQL

【思考1:自然分层设计和查询效率之间的取舍?】

【思考2:一般来说所有程序都是直接接到db,不需要db来区分,一个项目就一个db就好了?】

首先,为了更加具体而且没有那么枯燥,我先放张图——MySQL层次:

python中通过MySQLdb 这个模块完成与数据库链接等操作,然而有些系统并没有装这个模块,那么就要sudo pip install MySQL-python安装之。

这里存入MySQL数据库实现起来其实并不复杂,而且都是套路:喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">

def save_As_Mysql(extracted_data_):

print 'connecting to mysql....'

#套路一.链接数据库,别忘记开启MySQL服务

conn=MySQLdb.connect(

host='localhost',

port=3306,

user='root',

passwd='填你的Mysql数据库密码',

db='填你要接到的db名字',

charset='utf8'

)#charset指定连接编码格式

#套路二.创建游标

cur=conn.cursor()

#测试用

# sql_dropTable='drop table if exists '+str(from_city)+'到'+str(to_city)

# cur.execute(sql_dropTable)

# print '删除原表成功'

#套路三.创建表

sql_newTable='create table if not exists table_name(Field1 varchar(10),Field2 varchar(20))'

cur.execute(sql_newTable)

print '新表建立成功'

#套路四.往表中插入数据

sql_insert='insert into table_name values(%s,%s)'

cur.executemany(sql_insert,extracted_data_)#extracted_data_列表中列表

#cur.fetchall()

conn.commit()

cur.close()

conn.close()

更加准确来说其实MySQLdb要用到的只是套路一的链接数据库,套路二的创建游标,套路三的execute(sql,list/tuple)单次执行sql语句,套路四executemany(sql,[list,list,…]/[tuple,tuple,…])多次执行sql语句,conn.commit()把已经有的修改动作真实提交,cur.close()游标关闭,conn.close()链接关闭.

这些东西都是死的,我们真正起作用的地方是SQL语句的设计编写,MySQLdb只是负责execute或者executemany罢了

说明几点:

①MySQL中的字段类型之字符串

1.char(n):

定长,char不管实际value长度,都会占用固定的几个字符空间,速度快,而且处理字符串尾部空格,超过设置长度n的部分会截断

2.varchar(n):

变长,速度慢,不处理字符串尾部空格(UpperLimit:65535字节),超过设置长度n的部分会截断

3.text:

速度慢,不处理字符串尾部空格,而且会用额外空间去存放数据长度这个量

char(n)和varchar(n)中的n代表字符个数,并非代表字节个数,当使用中文(utf-8)时,意味着可以插入m个汉字,但是实际上会占用3m个字节,当然如果只是英文的话就是m个字母,实际上占用m个字节

当超过255长度后,varchar和text没有区别,只需要考虑两者类型和特性。

②SQL语句是str格式的

③mysql默认是lantin1编码,因为是由瑞典开发的.要改变的话,在mysql的shell下输入 set names utf8

有个花了我很久去解决的Error,我一定要在这里说出来- -#:

ProgrammingError:not all arguments converted during string formatting

TypeError:not all arguments converted during string formatting

解决办法:第一,请仔细check一下你的SQL语句有木有写错!第二,cur.execute()和cur.executemany()的区别和用法有没有弄清楚!

很不幸,我就是死在第二点,所以我要特别地在这里说说这两种的区别:

①cur.execute(sql,list/tuple),这里的list不能是那种list包括list的状况,只能单纯的一个list,比如[“16-8-26”,”16年08月30日”]这样的,而不是[[“16-8-26”,”16年08月30日”],[“16-8-26”,”16年08月31日”]]这样的列表嵌套列表,不然以我被它折腾了我一天的经验来看,分分钟给你报not all arguments converted during string formatting 。

②cur.executemany(sql,list-list/list-tuple),所谓list-list就是[[“16-8-26”,”16年08月30日”],[“16-8-26”,”16年08月31日”]]这种了,第一次就会取出list中的第一个list——[“16-8-26”,”16年08月30日”],过来就像execute时候一样,把这个取出的list中每一项取出放到前面的%s(占位符)位置,弄完了就去最外层list的第二个list,以此类推….

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值