存储方式
之前介绍的都是如何搭建环境、获取数据、解析html,这篇就介绍我使用过的小型数据存储方法。
- mysql存储,需安装pymysql库。数据转移不够方便,mysql适合大部分中型小型站点数据的存储。
- sqlite3存储,python3标准库。轻便,快速,单数据文件的sqlite3以及它在python3的原生支持的特性,使得它成为非常好的一个存储方案,配合ssd也有不错的性能。
文本存储(csv)存储,csv为标准库。不需要定义表结构,数据抽取不是很方便,适合数据结构简单的抓取。
下面是三种存储方式的示例,其中csv存储可以直接运行,mysql和sqlite3只是演示代码的使用,需要和表结构配合才能存储数据。import sqlite3 import pymysql import csv #sqlite3链接数据库 sqlite_file = 'my.db' CONN = sqlite3.connect(sqlite_file) CUR = CONN.cursor() #sqlite3插入数据 CUR.execute("INSERT INTO table (linkid,status_code)VALUES('{0[0]}','{0[1]}');".format(data)) CONN.commit() #sqlite3查询数据 CUR.execute('SELECT linkid FROM table ORDER BY linkid;') res = CUR.fetchall() #mysql链接数据库 CONN = pymysql.connect( host = '127.0.0.1', port = 3306, user = 'root', passwd = 'root', db = 'avmopw', charset = 'utf8' ) CUR = CONN.cursor() #mysql插入数据 CUR.execute("INSERT INTO table (linkid,status_code,datetime)VALUE('{0[0]}',{0[1]} ,now());".format(data)) CONN.commit() #mysql查询数据 sql = 'SELECT linkid FROM table ORDER BY linkid;' CUR.execute(sql) res = CUR.fetchall() #示例数据 items = [ ['1','LawnMower','Small Hover mower','Fred','$150','Excellent','2012-01-05'], ['2','LawnMower','Ride-on mower','Mike','$370','Fair','2012-04-01'], ['3','Bike','BMX bike','Joe','$200','Good','2013-03-22'], ['4','Drill','Heavy duty hammer','Rob','$100','Good','2013-10-28'], ['5','Scarifier','Quality, stainless steel','Anne','$200','2013-09-14'], ['6','Sprinkler','Cheap but effective','Fred','$80','2014-01-06'] ] csv_file = 'csv_file.csv' #存储csv文件 file = open(csv_file,'w',newline='') writer = csv.writer(file) for item in items: writer.writerow(item) file.close() #读取csv文件 file = open(csv_file) datareader = csv.reader(file); print(list(datareader))
豆瓣电影
我们尝试抓取豆瓣中电影排名top250,抓取排名,电影名,主演,导演,详情页链接,年份类别,是否可播放,评分,评价人数,和引用评价。这些信息都是在列表页面可以直接得到的,我们只需要抓取并不断翻页抓取下一页,就可以获得所有电影,最后我们使用sqlite3存储数据。
import requests
import sqlite3
import time
from lxml import etree
#获取页面链接
def page_url():
for page in [x for x in range(0,250,25)]:
yield 'https://movie.douban.com/top250?start={}&filter='.format(page)
def page_content():
headers = {
'Host':'movie.douban.com',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
'Referer':'https://movie.douban.com/top250?start=0&filter='
}
s = requests.Session()
s.headers = headers
data = {}
for url in page_url():
print('url',url)
html_str = s.get(url).text
html_tree = etree.HTML(html_str)
#获取页面中所有电影item中class为info的div
movie_tree = html_tree.xpath('//div[@id="content"]/div/div[@class="article"]/ol/li/div/div[@class="info"]')
for item in movie_tree:
item_data = {}
#电影链接
item_data['url'] = item.xpath('div[@class="hd"]/a/@href')[0]
#电影名称
item_data['name'] = ''.join(item.xpath('div[@class="hd"]/a/span/text()')).replace('\xa0',' ').replace("'","''")
#是否可播放
item_data['playable'] = item.xpath('div[@class="hd"]/span/text()')
if len(item_data['playable'])==1:
item_data['playable'] = item_data['playable'][0]
#导演演员
temp = item.xpath('div[@class="bd"]/p[1]/text()')[0].strip().replace("'","''").split('\xa0\xa0\xa0')
# print(temp)
#导演
item_data['director'] = temp[0].replace("'","''")
#演员
if len(temp)==2:
item_data['actor'] = temp[1].replace("'","''")
#类别
item_data['category'] = item.xpath('div[@class="bd"]/p[1]/text()')[1].strip().replace('\xa0',' ').replace("'","''")
#评分
item_data['rating_num'] = item.xpath('div[@class="bd"]/div/span[2]/text()')[0]
#多少人评价
item_data['people_num'] = item.xpath('div[@class="bd"]/div/span[4]/text()')[0]
#quote
try:
item_data['quote'] = item.xpath('div[@class="bd"]/p[2]/span/text()')[0].strip().replace("'","''")
except:
item_data['quote'] = ''
data[len(data)]=item_data
print(len(data))
time.sleep(3)
#调用sqlite3_save存储数据
sqlite3_save(data)
def sqlite3_save(data):
try:
CONN = sqlite3.connect('douban.db')
CUR = CONN.cursor()
CUR.execute('''
CREATE TABLE "movie_list" (
"id" INTEGER,
"name" TEXT(200),
"actor" TEXT(200),
"director" TEXT(200),
"url" TEXT(100),
"category" TEXT(200),
"playable" TEXT(50),
"rating_num" TEXT(10),
"people_num" TEXT(10),
"quote" TEXT(100),
PRIMARY KEY ("id")
);
''')
except:
pass
insert_sql = 'INSERT INTO movie_list (id,name,actor,director,url,category,playable,rating_num,people_num,quote) VALUES '
for id in data:
temp_sql = insert_sql + "('{1}','{0[name]}','{0[actor]}','{0[director]}','{0[url]}','{0[category]}','{0[playable]}','{0[rating_num]}','{0[people_num]}','{0[quote]}')".format(data[id],id+1)
try:
CUR.execute(temp_sql)
CONN.commit()
except:
pass
if __name__ == '__main__':
page_content()
以上就是示例,写得很简陋,里面也有很多我踩到的坑,这里把过程写出来。
1、在chrome中打开xpath匹配辅助工具“XPath Helper”,找到想要抓取的最小区域。
2、在这个区域中,分别找到我们想要抓取的信息。
3、执行爬虫,在cmd中查看运行情况
4、使用navicat查看抓取到的数据
一些小细节
replace('\xa0',' ')
\xa0
是空格,直接使用replace替换成空格
replace("'","''")
单引号在插入数据库时会报错,我们使用的是sqlite3数据库,所以我们把"'"替换成"''",也就是把一个单引号替换成两个单引号。
def page_url():
for page in [x for x in range(0,250,25)]:
yield 'https://movie.douban.com/top250?start={}&filter='.format(page)
这个函数使用了yield,是用于返回下一个url地址的生成器。