scrapy爬虫结果插入mysql数据库
简介
爬虫结构需要保存到数据库,以便于通过web界面进行操作,此处讲解了如何调用数据库的方法.
一、安装mysql驱动
在pycharm图形界面中无法安装,提示在命令行运行如下语句:
pip install --user --extra-index-url https://pypi.tuna.tsinghua.edu.cn/simple/ pymysql
执行上诉命令后如扔无法连接数据库,则去此地址下载http://www.codegood.com/downloads下载名为"MySQL-python-1.2.3.win-amd64-py2.7.exe"的驱动
俱乐部成员可在ftp://10.3.14.32 中下载python2.7的mysql驱动.其位置如下图所示:
二、在数据库中创建表格及存储过程
创建的表格如下图所示:
存储过程InsertAPIData代码如下:
BEGIN
#Routine body goes here...
#判断Api爬虫表中是否有相同的url,如果有,则只更新数据,否则,插入数据,避免爬虫爬取重复数据
declare _c int default 0; #定义整形变量c
set _c=(SELECT count(*) from CrawlAPI where Url=u); #通过select语句给变量赋值
#如果存在_url,则更新,否则,插入数据
IF _c=0 THEN
# 把api.1473.cn的所有网页链接及其标题,keywords,description插入数据库。
insert into CrawlAPI(ID,Url,Title,Keywords,Description,Content) VALUES(UUID(),u,t,k,d,c);
else
UPDATE CrawlAPI SET Title=t,Keywords=k,Description=d,Content=c WHERE Url=u;
SELECT _c;
end IF;
END
三、把爬到的结果保存到数据库
scrapy封装了连接数据库的方法,并且封装得很复杂,以下几个步骤缺一不可,否则不能把数据推送到数据库。
1、pipeline.py编写连接数据库的方法,链接数据库是用的twisted框架,此框架好像用得不多了!。使用此框架需要引入库:from twisted.enterprise import adbapi 这名字叫adbapi,比较醉人
其完整编码如下:
# -*- coding: utf-8 -*-
#引入twisted框架
from twisted.enterprise import adbapi
#引入scrapy的日志文件
from scrapy import log
#引用数据库驱动
import MySQLdb
#引用数据库游标
import MySQLdb.cursors
class MySQLPipeLine(object):
def __init__(self):
#其他参数均为字符串,port居然用整形。
self.dbpool = adbapi.ConnectionPool('MySQLdb', db='US_Crawler',user='root',host='10.20.5.88', passwd='usestudio-1',port=14062, cursorclass=MySQLdb.cursors.DictCursor,charset='utf8', use_unicode=True)
def process_item(self,item,spider):
#twisted架构固定写法
query=self.dbpool.runInteraction(self._conditional_insert,item)
query.addErrback(self.handle_error)
return item
def _conditional_insert(self,conn,item):
#调用存储过程方法
conn.execute('CALL InsertAPIData(%s,%s,%s,%s,%s)', (item['url'],item['title'],item['keywords'],item['description'],item['content']))
#log.msg("Item data in db:%s" %item,level=log.DEBUG)
def handle_error(self,e):
#错误处理
log.err(e)
2、item.py编写类,类中的字段为插入数据库的字段,相当于java中的实体模型,和数据库字段一一对应
其完整编码如下:
# -*- coding: utf-8 -*-
import scrapy
class ApiItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field()
url=scrapy.Field()
keywords=scrapy.Field()
description=scrapy.Field()
content=scrapy.Field()
3、在自己编写的爬虫文件(我的文件名为spider.py)中给tiem.py中的字段赋值。其涉及到数据库的编码如下:
#从response中获取内容,保存到数据库,为什么能保存到数据库呢?应该是架构写好的。
#extract方法返回unicode字符串
apiItem=ApiItem()
apiItem['url'] = response.url
# normalize-space 解决xpath取出的title值有很多回车空格的问题
#text()函数获取标签下面的文本
_titles=response.xpath(' normalize-space(/html/head/title/text())')
if _titles:
apiItem['title'] =_titles[0].extract()
else:
apiItem['title'] =""
#获取meta中的content比较麻烦,国内居然没有资料。
_keywords=response.xpath("//meta[@name='keywords']/@content")
if _keywords:
apiItem['keywords'] = _keywords[0].extract()
else:
apiItem['keywords'] = ""
_description=response.xpath("//meta[@name='description']/@content")
if _description:
apiItem['description'] = _description[0].extract()
else:
apiItem['description']=""
#首先获取body标签,然后再获取body标签中的所有字符串,为节约代码,下面使用三元操作符号,不熟悉的学生去学习一下三元
#python的三元比较奇葩,估计是不入流程序员写的,h = "变量1" if a>b else "变量2"
#_content=response.xpath('/html/body').xpath('string(.)').extract()[0];
_content=response.xpath('/html/body').xpath('string(.)')
apiItem['content']=_content[0].extract() if _content else ""
yield apiItem
4、在自己编写的爬虫文件(我的文件名为spider.py)中给tiem.py中的字段赋值。其完整编码如下:
#-*-coding:utf-8-*-
#支持中文必须加上上面一句话
__author__ = 'Administrator'
import scrapy
#正则表达式模块
import re
#包含scrapy中的Request请求,在yield request中用到
from scrapy.http import Request
#引入将要保存到数据库的类名称
from ApiCrawler.items import ApiItem
class ApiSpider(scrapy.spiders.Spider):
name = "api"
#只爬api.1473.cn网址
allowed_domains=["api.1473.cn"]
#开始爬的网址
start_urls=[
"http://api.1473.cn"
]
#目的是去除重复的url。
URLS=[]
#计数,一共爬了多少次
count=0
def parse(self, response):
#从response中获取内容,保存到数据库,为什么能保存到数据库呢?应该是架构写好的。
#extract方法返回unicode字符串
apiItem=ApiItem()
apiItem['url'] = response.url
# normalize-space 解决xpath取出的title值有很多回车空格的问题
#text()函数获取标签下面的文本
_titles=response.xpath(' normalize-space(/html/head/title/text())')
if _titles:
apiItem['title'] =_titles[0].extract()
else:
apiItem['title'] =""
#获取meta中的content比较麻烦,国内居然没有资料。
_keywords=response.xpath("//meta[@name='keywords']/@content")
if _keywords:
apiItem['keywords'] = _keywords[0].extract()
else:
apiItem['keywords'] = ""
_description=response.xpath("//meta[@name='description']/@content")
if _description:
apiItem['description'] = _description[0].extract()
else:
apiItem['description']=""
#首先获取body标签,然后再获取body标签中的所有字符串,为节约代码,下面使用三元操作符号,不熟悉的学生去学习一下三元
#python的三元比较奇葩,估计是不入流程序员写的,h = "变量1" if a>b else "变量2"
#_content=response.xpath('/html/body').xpath('string(.)').extract()[0];
_content=response.xpath('/html/body').xpath('string(.)')
apiItem['content']=_content[0].extract() if _content else ""
yield apiItem
# 下面的正则会提取页面中所有的后缀名为.aspx,.html .htm的超级链接,然后循环递归
pattern=re.compile(r'((((https|http):\/\/)|\/)[0-9a-zA-Z\/\.@-_%]*?\.(aspx|html|htm))')
urls=pattern.findall(response.text)
for url in urls:
#去除重复
findUrl=url[0]
if findUrl in self.URLS:
continue
else:
self.URLS.append(findUrl)
#Request对象需要包含from scrapy.http import Request
#递归获取
yield Request(findUrl,callback=self.parse)
三、twisted 调用存储过程方法
twisted调用存储过程资料太少,以下为其英文描述
You can use runInteraction to do arbitrary database or adapter specific things like this:
def aProcedure(cursor, arg1, arg2):
cursor.execute("CALL A_PROCEDURE(%s, %s)", (arg1, arg2))
return cursor.fetchall()
d = dbpool.runInteraction(aProcedure, arg1, arg2)
三、结束语
至此,爬虫的基础介绍完毕,剩下的部分涉及到分词,分词比较复杂,下一节做一个初步介绍,暂未实现
工作人员
作者:XXX
信息录入:XXX
文案编辑:XXX
视频录制:XXX
视频编辑:XXX
图片编辑:XXX
关键字修改:陈鑫