0. 前言
这是我在imooc上学习Scrapy框架的笔记,还附上了一个我为校内课程写的大作业(很简略),并在最后加上了我自己实践中遇到的一些问题的解决方法,希望能对大家学习、入门Scrapy有所帮助。
课程网址:
https://www.icourse163.org/course/BIT-1001870001?tid=1450316449
1. Scrapy框架结构
首先,spiders把request通过engine发送给scheduler(在这里,request可以理解为网页的url),然后由scheduler安排爬取。
然后,scheduler把request通过engine发送给downloader,downloader是真实从网页爬取数据的。爬取获得数据后,返回response给spiders。
最后,spiders处理该response后,产生了两个数据类:item和request。item是数据项,request是新的爬取请求(如果网页上有其他我们感兴趣的内容)。spiders将这两个数据类发送给engine,engine把item发给item pipeline,把request发送给scheduler。
在这个结构中,engine,downloader,scheduler都是已有实现的。用户只需自己编写spiders(入口)和item pipeline(出口)。其中,spiders提供url并解析response,而item pipeline负责提取的数据的后处理。
2. Scrapy框架结构解析
2.1 Engine
- 控制所有模块之间的数据流
- 根据条件触发事件
2.2 Downloader
- 根据请求下载网页
2.3 Scheduler
- 对所有爬取请求进行调度管理
2.4 Spiders
- 解析Downloader返回的响应(response)
- 产生爬取项(scraped item)
- 产生额外的爬取请求(request)
整个Scrapy框架的核心。负责提供url、解析数据……也是用户主要编写的部分。
2.5 Items Pipelines
- 以流水线方式处理Spiders产生的爬取项
- 由一组操作顺序组成,类似流水线,每个操作是一个Items Pipeline类型
- 可能操作包括:清理、检验、查重爬取项中的HTML数据、将数据存储到数据库。
用户需要关心的是:我们希望对提取出来的item类型的数据怎么做?是存储?还是其它?
3. Scrapy常用命令
Scrapy命令行格式:
scrapy <command> [options] [args]
其中,command是Scrapy的命令。具体如下:
-
startproject
创建一个新工程。格式:
scrapy startproject <name> [dir]
-
genspider
创建一个爬虫。格式:
scrapy genspider [options] <name> <domain>
-
settings
获得爬虫的配置信息。格式:
scrapy settings [options]
-
crawl
运行一个爬虫。格式:
scrapy crawl <spider>
-
list
列出工程中所有的爬虫。格式:
scrapy list
-
shell
启动url调试命令行。格式:
scrapy shell [url]
4. Scrapy基本使用
4.1 yield关键字
要了解yield,就要先了解生成器的概念。什么是生成器?
- 生成器是一个不断产生值的函数
- 包含yield语句的函数是一个生成器
- 生成器每次产生一个值(执行一个yield语句),函数被冻结,被唤醒后再产生一个值。
要注意的是,每次冻结之后唤醒生成器,代码还是从刚刚冻结的地方开始运行。这样,函数不停执行,就会源源不断地产生新的值。
生成器常和for循环搭配:
def gen(n):#生成小于n的数的平方
for i in range(n):
yield i**2
for i in gen(5):
print(i, " ")
上述代码得到结果:
0 1 4 9 16
相比于直接用列表形式返回给上层调用函数,生成器的优势是:
- 节省存储空间
- 响应更加迅速
- 使用更加灵活
实现同样的功能,列表形式需要存储许多的值。而生成器每次只产生存储一个值,再次调用时产生第二个值,所以只要一个值的存储空间。
4.2 简单实例
这里爬取的对象为中国天气网(上海未来多天的)天气信息。
第一步:
进入文件夹,创建项目:
scrapy startproject weather
创建完成!可以看到新生成的目录结构,有一个名字为weather的文件夹。该文件夹下,有以下文件或文件夹(这里挑选两个重点文件(夹)说明):
-
items.py
Items代码模板
-
spiders/
Spiders代码模板目录,存放爬虫。我们可以在这里生成爬虫。
第二步:
定义保存爬取内容的容器。在新建的WeatherItems.py里定义,当然,我们也可以直接在items.py里编写。
#引入文件
import scrapy
class WeatherItem(scrapy.Item):
#日期
date = scrapy.Field()
#天气状况
weather = scrapy.Field()
#最高温度
maxT = scrapy.Field()
#最低温度
minT = scrapy.Field()
#风向
direct = scrapy.Field()
#风力
wind = scrapy.Field()
第三步:
生产一个爬虫。
我们可以直接在spiders/文件夹下直接创建一个.py文件,也可以通过上述命令行格式来生成。生成的爬虫文件初始内容如下(这里我定义文件名为MySpider):
#引入文件
import scrapy
class MySpider(scrapy.Spider):
#用于区别Spider,爬虫的名字
name = "MySpider"
#允许访问的域
allowed_domains = [""]
#爬取的地址
start_urls = [""]
#爬取方法,解析内容
def parse(self, response):
pass
第四步:
配置爬虫。
设置好要爬取网页的url. 设计爬取方法parse,parse()方法负责处理response并返回处理的数据以及跟进的url.
在parse()方法中,我们可以使用任意的HTML信息提取方法,比如:Beautiful Soup, lxml,XPath,CSS Selector.这里使用的是XPath.
import scrapy
#引入容器
from weather.WeatherItems import WeatherItem
class MySpider(scrapy.Spider):
#设置name
name = "MySpider"
#设定域名
#allowed_domains = [""]
#填写爬取地址
start_urls = ["http://www.weather.com.cn/weather15d/101020100.shtml"]
#编写爬取方法
def parse(self, response):
item = WeatherItem()
for box in response.xpath('//ul[@class="t clearfix"]/li'):
#获取日期
item['date'] = box.xpath('./span[@class="time"]/text()').extract()[0].strip()
#获取天气信息
item['weather'] = box.xpath('./span[@class="wea"]/text()').extract()[0].strip()
#获取最高温度
item['maxT'] = box.xpath('./span[@class="tem"]/em/text()').extract()[0].strip()
#获取最低温度(这里因为网站上最低温度默认带了一个‘/’,所以去掉第零位,取字符串的第一位到最后一位)
item['minT'] = box.xpath('./span[@class="tem"]/text()').extract()[0][1:]
#获取风向
item['direct'] = box.xpath('./span[@class="wind"]/text()').extract()[0].strip()
#获取风力
item['wind'] = box.xpath('./span[@class="wind1"]/text()').extract()[0].strip()
yield item
第五步:
编写pipelines文件。我这里新建了一个名为MyPipelines.py的文件。也可以直接在pipelines.py文件下编写。spiders生成类似字典的键值对交由pipeline.把数据保存入data.json文件。
#引入文件
from scrapy.exceptions import DropItem
import json
class MyPipeline(object):
def __init__(self):
#打开文件
self.file = open('data.json', 'w', encoding='utf-8')
#该方法用于处理数据
def process_item(self, item, spider):
#读取item中的数据
line = json.dumps(dict(item), ensure_ascii=False) + "\n"
#写入文件
self.file.write(line)
#返回item
return item
#该方法在spider被开启时被调用。
def open_spider(self, spider):
pass
#该方法在spider被关闭时被调用。
def close_spider(self, spider):
pass
注册pipeline,在settings.py里有被注释掉的部分,去掉注释:
#ITEM_PIPELINES = {
# 'scrapytest.pipelines.MyPipeline': 300,
#工程名+文件名+类名}
第六步:
运行爬虫。命令行输入:
scrapy crawl MySpider
在设置好的data.json文件中就能看到结果。
5. 常见问题
正常来说,成功爬取到数据时终端会显示以下信息:
但有时,我们会发现自己爬不到任何数据,比如:
还没有爬到数据,spider就close了!这时有很多可能的原因,很有可能是因为网站本身对数据进行了加密或者有反爬虫技术,而不是我们的代码有问题。不要急,我们可以在命令行里一步步调试找到错误原因。具体操作步骤可以参见这篇博客:
https://blog.csdn.net/weixin_44841312/article/details/95670015