爬虫数据存储

爬取的数据,需要保存,可以存储在文件中或者数据库中。

  • 存储在文件中,包括txt、csv、json;
  • 存储在数据库中,包括MySQL关系数据库和MongoDB数据库。

python 字典操作参考:
http://jianwl.com/2017/08/22/高效实用Python字典的清单/

python 读写参考:
https://www.cnblogs.com/liutongqing/p/6892099.html

1、基本存储:存储至txt、csv、json

(1)存入txt文件(saving_data.py)

all_house数据结构:all_house[{'house_area':dd,'price':dd,'build_year':dd},{},{}...]

f=open('net_saving_data.txt','w');
for item in all_house:
    # house_area=item['house_area'];
    # price=item['price'];
    output='\t'.join([str(item['house_area']),str(item['price']),str(item['build_year'])]);
    f.write(output);
    f.write('\n');
f.close();

效果如图:

  • 若需要将几个变量写入txt中,可以用'\t'.join(["house_area","price","build_year"]),注意join()内是个列表

(2)存入CSV文件(saving_data.py)

CSV(Comma-Separated_values),以逗号分隔值的文件格式,文件以纯文本格式存储表格数据(数字和文本),每一行以换行符分隔,列与列之间用逗号分隔。与txt比较,能够存储的数据大小差不多,但是数据以逗号分隔较整齐,所有python网络爬虫经常用此来存储数据。

  • 从字典中写入csv文件
import csv;

f=open('net_saving_data.csv','w');
csv_write=csv.writer(f);
for item in all_house:
    csv_write.writerow([item.get('house_area',None),item.get('price',None),item.get('build_year',None)]);
    #f.write('\n');
f.close();

效果如图:

若是想在csv中加入key值,操作如下:

csv_write.writerow(['house_area',item.get('house_area',None),'price',item.get('price',None),'build_year',item.get('build_year',None)]);

效果如图:

  • 从列表中写入csv文件
houses=[['2edr','ser','sge'],['as','hi','hioh','aaajio']];
f=open('saving_data.csv','w');
csv_write=csv.writer(f);
for house in houses:
    csv_write.writerow([item for item in house]);
f.close();

效果如图:

(3)写入json文件

##写入
with open("anjuke_salehouse.json","w",encoding='utf-8') as f:
    json.dump(all_house,f,ensure_ascii=False);
    print(u'加载入文件完成...');

2、csv、json、txt读取:

(1)csv读取

-参考:https://www.cnblogs.com/liutongqing/p/6892099.html

import csv;
houses=[];
with open('net_saving_data.csv','r') as openscv:
    csv_reader=csv.reader(openscv);
    for row in csv_reader:
       houses.append(row); 
    openscv.close();
print houses;

原数据界面:

读取数据界面如下:

(2)json读取

##读入
with open("anjuke_salehouse.json",'r',encoding='utf-8') as f:
    load_dict=json.load(f);
print (load_dict);

什么的不要想,直接load出来的就是json文件格式一模一样的一个对象。 主要是防止乱码的等参数设置。

(3)txt读取

参考文章:https://blog.csdn.net/shandong_chu/article/details/70173952

with open('net_saving_data.txt','r') as opentxt:
    txt_reader=opentxt.readlines();
for lin in txt_reader:
    print (lin);

3、MySQL数据库操作

建库、更删改查,因为下面涉及一些对数据库的操作,现在这里复习一下基本的更删改查

(1)建数据库、建表

create table urls(id int NOT NULL auto_increment,url varchar(1000) NOT NULL,content varchar(4000) NOT NULL,created_time timestamp default current_timestamp,primary key(id));
*/

(2)查表结构或查database

describe urls;
show databases;

(3)表中插入数据

insert into urls(url,content)values("www.baidu.com","这是内容。")
select * from urls where id=1;

(4)从数据表中提取数据

insert into urls(url,content)values("www.blog.com","博客网址。");
select * from urls ;

(5)删除数据

delete from urls where url='www.baidu.com';
select * from urls ;

(6)修改数据
将id=2的content改成博客园

insert into urls(url,content)values("www.santostang.com","Santos blog");
update urls set url='www.blog.com',content="博客园" where id=2;
select * from urls ;

(7)语句参考地址:https://blog.csdn.net/ljxfblog/article/details/52066006

UNION

select * from a order by id) union (select * from b order by id);
  • 如果不同的语句中取出的行,有完全相同(这里表示的是每个列的值都相同),那么union会将相同的行合并,最终只保留一行。也可以这样理解,union会去掉重复的行。如果不想去掉重复的行,可以使用union all。如果子句中有order by,limit,需用括号()包起来。推荐放到所有子句之后,即对最终合并的结果来排序或筛选。两次查询的列数必须一致

JOIN

//使用连表查询
SELECT Persons.LastName, Persons.FirstName,Orders.OrderNo
FROM Persons, Orders
WHERE Persons.Id_P = Orders.Id_P 

//使用join查询(inner join)
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
INNER JOIN Orders
ON Persons.Id_P = Orders.Id_P
ORDER BY Persons.LastName



  • 有时为了得到完整的结果,我们需要从两个或更多的表中获取结果。我们就需要执行 join。 数据库中的表可通过键将彼此联系起来。主键(Primary Key)是一个列,在这个列中的每一行的值都是唯一的。在表中,每个主键的值都是唯一的。这样做的目的是在不重复每个表中的所有数据的情况下,把表间的数据交叉捆绑在一起。上面的例子中使用的 INNER JOIN(内连接),JOIN默认使用内连接,可以省略INNER。 我们还可以使用其他几种连接。

LEFT JOIN

//使用left join查询,只要左表有匹配的条件,就会生成一行,右表的列值为空。
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
LEFT JOIN Orders
ON Persons.Id_P=Orders.Id_P
ORDER BY Persons.LastName



RIGHT JOIN

//使用right join查询,只要右表有匹配的条件,就会生成一行,左表的列值为空。
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
RIGHT JOIN Orders
ON Persons.Id_P=Orders.Id_P
ORDER BY Persons.LastName



FULL JOIN

//使用full join查询,只要其中一个表中存在匹配,就会生成一行,另一个表的列值为空。
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
FULL JOIN Orders
ON Persons.Id_P=Orders.Id_P
ORDER BY Persons.LastName



  • JOIN: 如果表中有至少一个匹配,则返回行(INNER JOIN 与 JOIN)
  • LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
  • RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
  • FULL JOIN: 只要其中一个表中存在匹配,就返回行

ALTER

alter table urls add created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
#增加一列
alter table test modify content char(10) 
#修改表列类型

4、python操作MySQL数据库

参考文献:https://www.cnblogs.com/whatisfantasy/p/6134660.html

在操作数据库的时候,python2中一般使用mysqldb,但在python3中已经不在支持mysqldb了,我们可以用pymysql和mysql.connector。本文的所有操作都是在python3的pymysql下完成的。python -m pip install pymysql

mysql -u root -p
using mysql;
select host,user from mysql.user;

mysql的host、user、password等信息。

查询

conn=pymysql.connect(host='localhost',user='root',passwd='123456',db='scraping');
cur=conn.cursor();#获取方法,创建游标

sql='select * from urls';
recount=cur.execute(sql);#操作execute()方法写入sql语句
data=cur.fetchall(); # 返回数据,返回的是tuple类型
print data;
  • conn=pymysql.connect(host='localhost',user='root',passwd='123456',db='scraping')用于创建数据库的连接,里面指定参数(用户名,密码,主机信息)。cur=conn.cursor()通过获取的数据库连接conn下的cursor()方法来创建游标,之后通过游标操作execute()方法写入纯SQL语句。完成MySQL数据库操作后,需要关闭游标cur和连接conn。

插入数据

conn=pymysql.connect(host='localhost',user='root',passwd='123456',db='scraping');
cur=conn.cursor();

sql1='insert into urls(url,content)values(%s,%s)';
params=('www.sinlang.com','新浪微博');
recount=cur.execute(sql1,params);
##executemany 批量插入
li=[('www.blogs.com','批量插入的第一个'),('www.sou.com','批量插入的第二个')];
sql2='insert into urls(url,content)values(%s,%s)';
recount=cur.executemany(sql2,li);

sql3=sql='select * from urls';
recount=cur.execute(sql3);
data=cur.fetchall();
conn.commit;
cur.close;
conn.close;

print data;
#返回的都是元组((1,'','',time),(2,'','',time)...(6,'','',time));
  • 其中commit只要执行一次,以上都是返回元组。

插入数据,返回dict类型的数据

conn=pymysql.connect(host='localhost',user='root',passwd='123456',db='scraping');
cur=conn.cursor(cursor=pymysql.cursors.DictCursor);# 参数设置
sql='select * from urls';
recount=cur.execute(sql);

data=cur.fetchall();
cur.close();
conn.close();
print recount;
print data;
#返回的是列表含字典[{u'url': 'www.baidu.com', u'content': 'xxx', u'id': 1, u'created_time': datetime.datetime(2018, 8, 22, 22, 2, 23)}, {xxx}, {xxx}];

fechone来逐条获取数据或者for循环

  • for 循环获取数据
conn=pymysql.connect(host='localhost',user='root',passwd='123456',db='scraping');
cur=conn.cursor(cursor=pymysql.cursors.DictCursor);
sql='select * from urls';
recount=cur.execute(sql);

data=cur.fetchall();
for i in range(len(data)):
    print data[i]
cur.close();
conn.close();
print recount;
  • fechone来逐条获取数据
conn=pymysql.connect(host='localhost',user='root',passwd='123456',db='scraping');
cur=conn.cursor(cursor=pymysql.cursors.DictCursor);
sql='select * from urls';
recount=cur.execute(sql);

cur.close();
conn.close();
print recount;

for i in range(recount):
    data=cur.fetchone();
    print data;

两种方法获取结果都如下:

5、爬取网页数据存入MySQL数据库

(1) 在cmd 数据库中先创建database 和相应表;

create database anjuke;
use anjuke;
create table anjuke (id int not null Auto_increment,house_title varchar(1000) not null,house_layout varchar(1000) not null,house_area int not null,house_levers int not null,brokername varchar (1000),address varchar(2000),price int not null,primary key(id));

(2)将数据插入数据库中,爬取的数据格式如下[{},{},{},{}]。for循环列表,提取每一个字典中的信息,建立sql语义传参至execute中。

conn=pymysql.connect(host='localhost',user='root',passwd='123456',db='anjuke');
cur=conn.cursor();
for item in all_house:
    house_title=item['house_title'];
    house_layout=item['house_layout'];
    house_area=item['house_area'];
    house_levers=item['house_levers'];
    brokername=item['brokername'];
    house_address=item['house_address'];
    price=item['price'];
    sql='insert into anjuke(house_title,house_layout,house_area,house_levers,address,brokername,price) values (%s,%s,%s,%s,%s,%s,%s)';
    #parme=(house_title,house_layout,house_area,house_levers,house_address,brokername,price);
    #cur.execute(sql,parme);
    cur.execute(sql,(house_title,house_layout,house_area,house_levers,house_address,brokername,price));
conn.commit();
cur.close();
conn.close();

(3) 读取存入MySQL数据库de网页爬取数据,可以[{},{},{}...{}]或者{}/n{}/n{}/n.../n{}形式输出。

conn=pymysql.connect(host='localhost',user='root',passwd='123456',db='anjuke');
cur=conn.cursor(cursor=pymysql.cursors.DictCursor);
sql='select * from anjuke';
cur.execute(sql);
conn.close();
cur.close();
data=cur.fetchall();#[{},{},{}...{}]
print data;
conn=pymysql.connect(host='localhost',user='root',passwd='123456',db='anjuke');
cur=conn.cursor(cursor=pymysql.cursors.DictCursor);
sql='select * from anjuke';
recount=cur.execute(sql);
conn.close();
cur.close();
for i in range(recount):
    data=cur.fetchone();
    print data;
  • 可close()后,再对cur进行data的输出。

总结 NOTE

  • 数据存至txt csv有固定格式,记住就好
  • 存到mysql,主要是连接数据库:conn=mysql.connect()、获取游标:cur=conn.cursor、对数据库操作:cur.execute(sql)、获取数据库:cur.fetchall()四个操作进行数据库操作。一般获取后,可以不用commit,存入数据等需要conn.commit(),但都要conn.close(),cur.close()
  • 另外深入可参考:http://www.runoob.com/python/python-mysql.html
posted @ 2018-08-27 17:11  msay  阅读(1189)  评论(0编辑  收藏  举报