有思俱乐部学习园地

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
关键字修改:陈鑫