爬虫scrapy总结笔记
1.声明一下:
提醒一下,爬虫有风险,我在前几天用学校的ip做爬虫测试,导致人家服务器nginx报错,吓死人了,所以爬虫太快相当于Ddos攻击,要坐牢的!!
猫眼电影知道我们很多学生都是拿他做测试,他的反爬措施就是让我们手动拉滑块,防止我们太快,已经是非常良心的了,一般一个ip整站抓取,只要不是太快,一般可以完成,但是就是别快,快了就是给你封ip
然后我继续提醒一下:我对爬虫的运行方式已经非常的清楚写的了,这个是我写的总结性笔记
1.创建项目
#创建爬虫项目
scrapy startproject Maoyan
#创建爬虫文件
cd Maoyan
scrapy genspider maoyan maoyan.com
Scrapy基本组件
- 引擎(Engine)----------整个框架核心
- 爬虫程序(Spider)------数据解析提取
- 调度器(Scheduler)-----维护请求队列
- 下载器(Downloader)----获取响应对象
- 管道文件(Pipeline)-----数据入库处理
scrapy项目目录结构
Maoyan # 项目文件夹
├── maoyan # 项目目录
│ ├── items.py # 定义数据结构
│ ├── middlewares.py # 中间件
│ ├── pipelines.py # 数据处理
│ ├── settings.py # 全局配置
│ └── spiders
│ ├── maoyan.py # 爬虫文件
└── scrapy.cfg # 项目基本配置文件
2.创建项目的基本步骤
【1】新建项目和爬虫文件
scrapy startproject 项目名
cd 项目文件夹
新建爬虫文件 :scrapy genspider 文件名 域名
【2】明确目标(items.py)
【3】写爬虫程序(文件名.py)
【4】管道文件(pipelines.py)
【5】全局配置(settings.py)
【6】运行爬虫
1) 终端: scrapy crawl 爬虫名
2) pycharm运行
a> 创建run.py(和scrapy.cfg文件同目录)
#共两行
from scrapy import cmdline
cmdline.execute('scrapy crawl maoyan'.split())
b> 直接运行 run.py 即可
3.创建项目的基本步骤实现
tips:这个只是get请求的项目
1.新建项目和爬虫文件
#初始化一个爬虫项目(这边的名字不能和爬虫文件名一样,所以我这边第一个首字母设置了大写)
scrapy startproject Maoyan
#进行项目目录
cd Maoyan
#scrapy genspider 爬虫文件名 爬虫目标网址(根网址)
scrapy genspider maoyan maoyan.com
2.明确需要抓取什么信息
- 电影名称
- 主演
- 时间
我需要这三个信息,我就是scrapy项目中的items文件中写入三个
"""items.py"""
import scrapy
class MaoyanItem(scrapy.Item):
name = scrapy.Field()#电影名称
star = scrapy.Field()#主演
time = scrapy.Field()#时间
3.写爬虫程序(位于spider文件下的maoyan.py)
在这里有一个重点
因为猫眼是通过url的offset=页数,然而scrapy给的start_url有一个很大的局限性,所以我就打算重新写一个方法代替start_url
start_url:就是在程序第一次启动的时候,去请求的链接,一个链接就请求一次,如果有成千上万条请求那不就GG了
猫眼电影翻页逻辑
https://maoyan.com/board/4?offset=0 #第一页
https://maoyan.com/board/4?offset=10 #第二页
····
https://maoyan.com/board/4?offset=90 #第十页
所以重新写一个方法,代替start_url
方法如下:
def start_requests(self):
for page in range( 0, 91, 10):
url = f'https://maoyan.com/board/4?offset={page}'
yield scrapy.Request(url=url,callback=self.parse)#把url一次性传到调度器,让调度器传给下载器
#yield方法相当于return ,但是又有点像next, 返回再继续,返回再继续,直到什么都没了
#callback非常重要,他代表了下载器请求完数据需要到那个解析进行处理(在maoyan.py中的parse)
然后咱们之前有写了一个items文件,即确定要提取的字段,把他引入到爬虫文件中
#引入items
from ..items import MaoyanItem
#怎么使用呢?
"""
item = MaoyanItem()
#然后咱们不是有三个数据需要抓取的
分别为
item['name'] = 解析以后的数据
item['star'] = 解析以后的数据
item['time'] = 解析以后的数据
yield item
#提交上去给管道
"""
完整代码如下:(在这里是spider文件夹下的maoyan.py)
# -*- coding: utf-8 -*-
import scrapy
from ..items import MaoyanItem
class MaoyanSpider(scrapy.Spider):
name = 'maoyan'
allowed_domains = ['maoyan.com']
# 1.去掉start_urls
# 2.重写start_requests()
def start_requests(self):
for offset in range(0, 91, 10):
url = 'https://maoyan.com/board/4?offset={}'.format(offset)
# 交给调度器入队列
yield scrapy.Request(url=url, callback=self.parse_html)
def parse_html(self, response):
dd_list = response.xpath('//dl/dd')
for dd in dd_list:
item = MaoyanItem()
item['name'] = dd.xpath('.//p[@class="name"]/a/text()').get().strip()
item['star'] = dd.xpath('.//p[@class="star"]/text()').get().strip()
item['time'] = dd.xpath('.//p[@class="releasetime"]/text()').get().strip()
print(item)
# 交给项目管道处理
yield item
4.管道文件(数据保存的地方)** 新的方法记得去注册哦! **
在这个时候传给管道的文件就已经是非常完美了
大概这个时候数据是这个样子的
{'name':'喜羊羊与灰太狼','star':'未知','time':'2000年'}
·······
{'name':'XXXXXX','star':'XX','time':'XXX'}
然后就是开始数据持久化
按照比赛要求,数据的格式为:
1.csv
2.json
3.Mysql
由于csv和json都是有固定格式的,scrapy所以就帮我们封装好了,but,我们必须自己手写一个方法
首先一进到管道文件的样子是:方法的最后面必须加上 return item 这个非常重要
现在只要在爬虫名后面添加 -o 文件名.csv
或者 -o 文件名.json(json因为默认不输出utf-8),如果不设置编码会乱码,具体怎么做,我就不想写了,因为百度可以百度到,可以这么写,scrapy输出json乱码
如果你要拿csv(因为scrapy封装,但是有一个很大的问题,就是顺序)
我之前的顺序是,name,star,time,如果只是有scrapy的方法,他不会按照你的顺序,所以我直接写了一个方法
from scrapy import cmdline
cmdline.execute('scrapy crawl maoyan -o maoyan.csv'.split())
要拿json的话,就去把maoyan.csv改成maoyan.json(不过要注意编码,一行就能解决,但是我就不说,自己百度)
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
class MaoyanPipeline(object):
def process_item(self, item, spider):
print(item) #{'name': '网络谜踪', 'star': '主演:约翰·赵,米切尔·拉,黛博拉·梅辛', 'time': '上映时间:2018-12-14'}
return item #return item非常重要,必须写
So·····
接下来要做的:我现在的想法是把scrapy自带的MaoyanPipeline方法留着,自己写三个,分别存在csv文件、json文件和Mysql数据库
为了能够解释清楚:管道的基本用法:
class SomethingPipeline(object):
def __init__(self):
# 可选实现,做参数初始化等
# 就是初始化,就是相当于王者荣耀开局的200金币,后面就不会在有这种待遇,想要有这个待遇就是开下一局
def process_item(self, item, spider):
# item (Item 对象) – 爬取数据的item
# spider (Spider 对象) – 爬取该item的spider
# 这个方法必须实现,每个item pipeline组件都需要调用该方法,
# 这个方法必须返回一个 Item 对象,被丢弃的item将不会被之后的pipeline组件所处理。
return item
def open_spider(self, spider):
# spider – 被开启的spider
# 可选,spider开启时,这个方法被调用。
def close_spider(self, spider):
# spider – 被关闭的spider
# 可选,spider关闭时,这个方法被调用
1.csv文件
重要!重要!重要!
写完代码以后要先去settings.py文件中进行管道注册
写完代码以后要先去settings.py文件中进行管道注册
写完代码以后要先去settings.py文件中进行管道注册
!!否则无法使用!!
#相当于有了驾照才能上路,scrapy也要在settings里面进行注册,才能让我们写的方法合法运行
ITEM_PIPELINES = {
'Maoyan.pipelines.MaoyanPipeline': 300,
'Maoyan.pipelines.Maoyan_csv_Pipeline':299,
'Maoyan.pipelines.Maoyan_json_Pipeline':269,
'Maoyan.pipelines.Maoyan_Mysql_Pipline':209,
}
思路:
1.先初始化,然后在初始化写入表头
def __init__(self):
# csv文件的位置,无需事先创建
store_file = os.path.dirname(__file__) + '/CSV/maoyan.csv'
# 打开(创建)文件
self.file = open(store_file, 'w',newline='',encoding='utf-8')
# csv写法
self.writer = csv.writer(self.file)
#创建表头
self.writer.writerow(['电影名字','电影主演','电影上映时间'])
2.然后插入数据
def process_item(self, item, spider):
if item['name']:
self.writer.writerow([item['name'],item['star'],item['time']])
return item
else:pass
3.爬虫结束关闭文件
def close_spider(self,spider):
self.file.close()
4.一个保存csv文件保存完整代码
class Maoyan_csv_Pipeline(object):
def __init__(self):
# csv文件的位置,无需事先创建
store_file = os.path.dirname(__file__) + '/CSV/maoyan.csv'
# 打开(创建)文件
self.file = open(store_file, 'w',newline='',encoding='utf-8')
# csv写法
self.writer = csv.writer(self.file)
#创建表头
self.writer.writerow(['电影名字','电影主演','电影上映时间'])
def process_item(self, item, spider):
if item['name']:
self.writer.writerow([item['name'],item['star'],item['time']])
return item
else:pass
def close_spider(self,spider):
self.file.close()
来一个截图,嘿嘿,不过提醒一下,编码问题 虽然简单,但是很重要哦
简单在于,网页是什么编码我们就是什么编码
重要在于,你不写就会乱码(一堆符号,看不懂 =呜呜呜=)
2.json文件
首先先看看json的基本格式:
{ "people": [
{ "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },
{ "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },
{ "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }
]}
3.Mysql数据库
完整代码如下:
class Maoyan_Mysql_Pipline:
def open_spider(self,spider):
self.db = pymysql.connect(host='localhost',user='xiaochen',port=3306,password='123456',db='Maoyan',charset='utf8mb4')
self.cur = self.db.cursor()
self.ins = 'insert into tb_maoyan values (%s,%s,%s)'
def process_item(self, item, spider):
li = [
item['name'],
item['star'],
item['time']
]
self.cur.execute(self.ins,li)
self.db.commit()
time.sleep(0.1)
return item
def close_spider(self,spider):
self.cur.close()
self.db.close()