Python:scrapy 爬取40天天气预报

爬虫对象选择

打开中国天气网站,例如我要爬取厦门近 40 天的天气情况,打开对应的网页。“weather40d”目录是近 40 天的天气,“101230201”是厦门城市的 id。

http://www.weather.com.cn/weather40d/101230201.shtml


打开开发者工具,观察到每一天的天气数据还是比较复杂的,所以我们还是要找 API。

在 network 中观察,Fetch/XHG 中没有任何请求的交互,说明这个网页要么是静态的,要么是用 JavaScript 动态生成的。

随便找一个在页面中的字符串,例如以 11 月 7 号的天气“多云转小雨”为例,可以看到搜索出一个结果。

查看这个 JavaScript 文件,可以看到这里罗列了一系列的数据。

打开详细的数据,发现这个字典里面的数据可以和网页的数据对应,说明这个就是我们想要的 js 文件。

查看这个请求的请求头,得到这个 js 文件的 url。

但是访问这个 url,发现回显 403 错误。403 错误表示资源不可用,也就是服务器理解客户的请求,但拒绝处理它,通常由于服务器上文件或目录的权限设置导致的。

也就是说只有特定的地方发起请求才能获取这个资源,查看请求头,发现 “Referer” 字段的值为中国天气网站。Referer 字段用于告诉服务器该网页是从哪个页面链接过来的,因此很有可能我们想要的 js 文件只接受来源于该网站的请求。同时还有一个“User-Agent”字段也需要设置,User-Agent 字段会告诉网站服务器访问者是通过什么工具来请求的。

创建 scrapy 工程

Scrapy 是适用于 Python 的一个快速、高层次的屏幕抓取和 web 抓取框架,用于抓取 web 站点并从页面中提取结构化的数据,提供了多种类型爬虫的基类。

和之前用 requests 库不同,要使用 Scrapy 框架需要创建一个 Scrapy 工程,可以在 cmd 使用命令创建。

scrapy startproject 工程名

Scrapy 的项目的目录结构如下:

scrapy.cfg
myproject/
    __init__.py
    items.py
    pipelines.py
    settings.py
    spiders/
        __init__.py
        spider1.py
        spider2.py
        ...

接着可以进入目录下进行初始化,使用命令指示要爬取的 Url,Scrapy 会为之建立一个爬虫文件。

cd 工程名
scrapy genspider 爬虫名 Url

例如我新建一个工程 weather,并且初始化一个爬虫文件 XMWeather 并指定 url 如下。

scrapy startproject weather
cd weather
scrapy genspider XMWeather http://d1.weather.com.cn/calendar_new/2021/101230201_202111.html

代码编写

items.py

Scrapy 提供 Item 类,实例化后的 Item 对象是种简单的容器,用于保存了爬取到得数据。其提供了类似于字典的 API 以及用于声明可用字段的简单语法,Item 使用简单的 class 定义语法以及 Field 对象来声明。
注意由于我们爬取的是包含 JSON 字符串的 JavaScript 文件,所以只需要将 JSON 字符串存起来即可,所以 Item 里面只有一个 content 字段。

import scrapy

class WeatherItem(scrapy.Item):
    content = scrapy.Field()

spiders/XMWeather.py

Spider 类定义了如何爬取网站,包括了爬取的动作以及如何从网页的内容中提取结构化数据。当我们编写 Spider 类时需要在 spiders 文件夹下创建 py 文件,由于我们刚刚有初始化所以这里已经有一个 py 文件了。
Scrapy 爬取之后将返回一个 response 对象,parse() 是处理下载的 response 的默认方法,这个方法应该将数据处理后填充进一个实例化后的 Item 类对象中并返回。使用 response.body_as_unicode() 可以获得 response 对象的内容,由于我定义的 Item 只有一个字段,所以设置这个字段并返回即可。

import scrapy

from weather.items import WeatherItem

class XmweatherSpider(scrapy.Spider):

    name = 'XMWeather'
    allowed_domains = ['d1.weather.com.cn']
    start_urls = ['http://d1.weather.com.cn/calendar_new/2021/101230201_202111.html']

    def parse(self, response):
        #实例化 Item 对象
        item = WeatherItem()
        item['content'] = response.body_as_unicode()[11:]
        return item

观察 Response 的内容,发现除了开头的 “var fc40 = [”这一串字符串,后面的内容都是以 json 的格式存在的。所以只需要把一开始的 “var fc40 = [”删掉,请求的内容就可以以 JSON 的格式解析。

pipelines.py

当 Item 在 Spider中被收集之后,它将会被传递到 Item Pipeline,pipelines.py 中的组件将会按照一定的顺序执行对 Item 的处理。每个 item pipeline 组件是实现了简单方法的 Python 类,接收到 Item 后将执行一些行为进行处理,例如存储入文件当中。
此处我编写了 WeatherPipeline 类用于将 item 中的 content 字段解析为 JSON 对象,然后存储如 xls 文件中。

from itemadapter import ItemAdapter
import json
import xlwt

class WeatherPipeline:
    def process_item(self, item, spider):
    
        weathers = json.loads(item['content'])
        writebook = xlwt.Workbook()
        sheet = writebook.add_sheet('Sheet1')
        keys = ['date','nlyf','nl','w1','wd1','max','min','jq','t1','hmax','hmin','hgl','alins','als']
        for i in range(len(keys)):
            sheet.write(0, i, keys[i])
        for i in range(len(weathers)):
            for j in range(len(keys)):
                sheet.write(i + 1, j, weathers[i][keys[j]])
        writebook.save('weathers.xls')

settings.py

Scrapy 的 settings 提供了定制 Scrapy 组件的方法,可以控制包括核心、插件、pipeline 及 spider 组件。设定为代码提供了提取以 key-value 映射的配置值的的全局命名空间,settings 同时也是选择当前激活的 Scrapy 项目的方法。
由于 url 有来源检测,所以我们要设置 DEFAULT_REQUEST_HEADERS 修改报文的请求头。ITEM_PIPELINES 则是指定了用来处理数据的 Pipeline,后面的值表示的是优先级。

BOT_NAME = 'weather'

SPIDER_MODULES = ['weather.spiders']
NEWSPIDER_MODULE = 'weather.spiders'

ROBOTSTXT_OBEY = True

DEFAULT_REQUEST_HEADERS = {
    "Referer":"http://www.weather.com.cn/",
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
}

ITEM_PIPELINES = {
    'weather.pipelines.WeatherPipeline': 300
}

项目运行

在项目目录下使用 scrapy crawl 命令可以运行该项目,也可以加上 nolog 使其不输出日志信息。

scrapy crawl 爬虫名
scrapy crawl 爬虫名 --nolog

运行项目之后的效果如下:

scrapy crawl XMWeather --nolog


参考资料

Scrapy 0.24 文档

原文地址:https://www.cnblogs.com/linfangnan/p/15566417.html