Scrapy爬数据并存储到mysql中
2017-08-14 14:11
393 查看
前言
看这篇文嘉,假设你已经:1. 安装了Srcapy框架
2. 安装了mysql
3. import了pymysql
后面两个可以参考我的前一篇博客,请移步:Python3.x连接Pymysql
首先来说说我踩的坑
坑1
我定义好items后,下一步是要将items这个容器引入到我的spider里面。所以要在spider文件中写上这么一句话:from scrapytest.CourseItems import CourseItem
scrapytest是我的工程名,CourseItem是我的item的类名。但是这句话在我的notebook里面死活给我报错:
No Module named "scrapytest"
What?我的scrapytest好好的在那啊。然后我建立一个同层的py文件,就是好的,所以我推测可能在notebook上面没有这种导入吧。
坑2
我最后爬的数据,根本就存储不到数据库中,所以我检查了几个步骤来排查原因:1.到底有没有爬到数据?
我写了一个生成json文件的类,然后去看了我保存下来的json,里面是有数据的,所以是数据库插入的问题。
2.在连接“数据池“的时候出现了问题?
我在连接函数的内部打了log,结果可以打印log,所以连接数据库没问题。
3.数据库启动了没?
我重新写了一个简单的插入,用的是这里同样的代码,不过是把相对的数据改为绝对的数据。结果是可以存储的。所以得出结论,数据库人家好好的。
4.数据的问题?
由上一步的一些结论,我发现我的相对数据不行,但是改成绝对数据的话,就可以存储。所以我的数据格式有问题。我打印了我的数据,发现都是list,而且price还是list里面套着list。那么就知道是price的格式不对,导致我老是报错:(此处感谢帮我调了一天bug的orangesdk[可调戏])
说我没有送进去数据,它必须要一个数据才行。所以我追根溯源,去看price爬取的时候我写的xpath:
item['price'] = response.xpath('//div[@class="item-mod"]/div[@class="favor-pos"]/p[@class="price"]/span/text()').extract()
我想着数组里面套数组,肯定就是数据爬多了,所以得再精确地定位一下这个price。把前面的//div[@class=”item-mod”]删除:
item['price'] = response.xpath('//p[@class="price"]/span/text()').extract()
price格式好了之后,就可以插入了。
我们开始建立Srcapy项目
安装Scrapy这里就不再赘述了,然后就是执行以下命令新建一个Scrapy项目:scrapy startproject scrapytest
【scrapy是我项目的名字,可以任意更改。】
然后就可以看到我们生成好的一个scrapy项目:
我们主要用的就是这四个文件:items、pipelines.py、settings.py、spiders下面的spider.py。先分别说说它们怎么用:
1.items.py:
定义你想要爬的东西的名字:
import scrapy class HouseItem(scrapy.Item): #名称 name = scrapy.Field() #区域 region = scrapy.Field() #价格 price= scrapy.Field()
等号后面的scrapy.Field()是固定搭配,HouseItem是我的item的类名,其实我这个文件叫做HouseItem.py,我在item.py的同一层新建的,跟直接在item.py里面写的效果是一样的。
2.pipelines.py
pipelines里面是写其他操作类的。比如写一个类专门向数据库中插值,一个类专门生成json。向数据库中插值代码如下:
from scrapy import log import pymysql import pymysql.cursors import codecs from twisted.enterprise import adbapi class WebcrawlerScrapyPipeline(object): @classmethod def from_settings(cls, settings): dbargs = dict( host=settings['MYSQL_HOST'], db=settings['MYSQL_DBNAME'], user=settings['MYSQL_USER'], passwd=settings['MYSQL_PASSWD'], port=settings['MYSQL_PORT'], charset='utf8', cursorclass=pymysql.cursors.DictCursor, use_unicode=True, ) dbpool = adbapi.ConnectionPool('pymysql', **dbargs) return cls(dbpool) def __init__(self,dbpool): self.dbpool=dbpool 4000 #pipeline默认调用 def process_item(self, item, spider): d=self.dbpool.runInteraction(self._conditional_insert, item, spider)#调用插入的方法 log.msg("-------------------连接好了-------------------") d.addErrback(self._handle_error,item,spider)#调用异常处理方法 d.addBoth(lambda _: item) return d def _conditional_insert(self, conn, item, spider): log.msg("-------------------打印-------------------") conn.execute("insert into test (name, region, price) values(%s, %s, %s)", (item['name'], item['region'], item['price'])) log.msg("-------------------一轮循环完毕-------------------") def _handle_error(self, failue, item, spider): print(failue)
我们可以改的东西:
类名可以改
cursorclass=pymysql.cursors.DictCursor里面的pymysql,是因为我用的是pymysql,如果你是python3.4以前的版本的话,你可以使用MySQLDB。
dbpool = adbapi.ConnectionPool('pymysql', **dbargs)这个里面的pymysql同上.
“_conditional_insert” 这个方法的方法名可以改,如果更改的话,上面的
d=self.dbpool.runInteraction(self._conditional_insert, item, spider)调用的名字也要改.
“_conditional_insert” 插入的sql语句:
conn.execute("insert into test (name, region, price) values(%s, %s, %s)",(item['name'], item['region'], item['price']))
这句话一定要写对。test是表名,在执行这个操作之前,你要确保你的数据库里面有这个表。表里面的字段有你item里面的那几个字段,这些都是一一对应的。
3.settings.py
settings最重要的就是要加上两个设置:
引入前面你写的类,并附上优先级(后面的数字就是优先级,数字越小越优先执行)。
ITEM_PIPELINES = { 'scrapytest.MyPipelines.WebcrawlerScrapyPipeline': 300, 'scrapytest.MyPipelines.MyPipeline': 1, }
添加数据库信息。如果是本地的,就写上localhost,如果连接的是远程的mysql数据库,则直接写远程的ip。
MYSQL_HOST = 'localhost' MYSQL_DBNAME = 'test' #数据库名字,请修改 MYSQL_USER = 'root' #数据库账号,请修改 MYSQL_PASSWD = 'root' #数据库密码,请修改 MYSQL_PORT = 3306 #数据库端口
4.spiders下面的spider.py
import scrapy from scrapytest.HouseItems import HouseItem class MySpider(scrapy.Spider): name = "MySpider" # 设定域名 allowed_domains = ["anjuke.com"] # 填写爬取地址 start_urls = [ 'https://xa.fang.anjuke.com/loupan/all/p%s/' % p for p in range(1, 15) ] # 编写爬取方法 def parse(self, response): # 实例一个容器保存爬取的信息 item = CourseItem() # 这部分是爬取部分,使用xpath的方式选择信息,具体方法根据网页结构而定 item['name'] = response.xpath('//div[@class="infos"]/div[@class="lp-name"]/h3/a[@class="items-name"]/text()').extract() item['region'] = response.xpath('//div[@class="infos"]/p[@class="address"]/a[@class="list-map"]/text()').extract() item['price'] = response.xpath('//p[@class="price"]/span/text()').extract() yield item
需要注意:
一定要引入你的Items文件,如果不引入会不知道你要爬哪个,会说你下面的item都没有定义。
一定要写上name。这里我的name是叫“MySpider”。因为有时候可能会并行几个爬虫,名字可以用来区分。而且当你运行整个项目的时候,也是直接运行爬虫。执行的命令行需要输入名字。
item一定要先初始化。
item = HouseItem()。给它初始化一下,才能知道后面我们定义的都是什么。
Xpath一定要写对。Xpath的语法网上有很多,这里不再详述,可以自行百度。(我往往出错都是Xpath没写对= =)
Xpath后面不要忘记写.extract()。
最后来一个yield item一定不能忘记。yield的意思是把你获取的抛出后,继续执行这个函数。和return的区别就是会继续执行,而return不会继续。
## 运行我们的Srcapy项目
进入项目目录之后,执行:
Scrapy crawl MySpider
就可以在数据库中看到结果了。看不到结果的,请参照我前面写的坑2的调试方法。
memoryjdch编辑于2017.8.18
相关文章推荐
- 用scrapy-redis爬去新浪-以及把数据存储到mysql\mongo
- Scrapy爬数据并存储到mysql中
- scrapy将数据存储到mysql中
- python,scrapy爬虫sql之爬取数据存储到mysql的piplelines.py配置
- scrapy 数据存储mysql
- python网络爬虫-数据存储之MySQL
- MySql的sql语句中添加存储过程或者存储函数来实现Oracle中的start with ……connect by prior……递归(树形结构数据)查询
- mysql 存储过程一个简单的循环遍历操作数据
- mysql下以标准时间格式输出存储的时间戳数据
- MySQL存储引擎和数据类型
- Mysql创建用户表并利用存储过程添加100万条随机用户数据
- MySQL 数据类型与存储长度
- 分布式数据存储 - MySQL主从复制高可用方案
- 修改mysql数据存储的地址
- 在Mysql中用 LONGBLOB 类型存储二进制数据
- 向MySQL 中存储大文本数据
- 第三十一天 MySQL并发控制、存储引擎介绍、用户权限管理、缓存管理和数据类型选择
- Centos7.3,mysql5.7环境,数据存储空间加大调整方案。
- mysql更换数据存储目录
- MySQL 存储数据时 乱码问题