基于scrapy爬虫的天气数据采集(python)
基于scrapy爬虫的天气数据采集(python)
一、实验介绍
1.1. 知识点
本节实验中将学习和实践以下知识点:
- Python基本语法
- Scrapy框架
- 爬虫的概念
二、实验效果
三、项目实战
3.1. 安装Scrapy
安装 scrapy-0.24:
# 安装依赖的包
$ sudo apt-get update
$ sudo apt-get install python-lxml python-dev libffi-dev
# 更新系统默认的 six 包
$ sudo pip install six --upgrade
# 安装指定版本的scrapy
$ sudo pip install scrapy==0.24.4
完成这步后,可以用下面的命令测试一下安装是否正确:
$ scrapy version
如果正常,效果如图所示:
3.2. 创建项目
在开始爬取之前,必须创建一个新的Scrapy项目。进入您打算存储代码的目录中,运行下列命令:
$ scrapy startproject weather
如果正常,效果如图所示:
这些文件分别是:
- scrapy.cfg: 项目的配置文件
- weather/: 该项目的python模块。之后将在此加入代码。
- weather/items.py: 项目中的item文件.
- weather/pipelines.py: 项目中的pipelines文件.
- weather/settings.py: 项目的设置文件.
- weather/spiders/: 放置spider代码的目录.
3.3. 定义Item
Item 是保存爬取到的数据的容器;其使用方法和python字典类似,并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。
首先根据需要从weather.sina.com.cn获取到的数据对item进行建模。 我们需要从weather.sina.com.cn中获取当前城市名,后续9天的日期,天气描述和温度等信息。对此,在item中定义相应的字段。编辑 weather 目录中的 items.py 文件:
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class WeatherItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# demo 1
city = scrapy.Field()
date = scrapy.Field()
dayDesc = scrapy.Field()
dayTemp = scrapy.Field()
pass
3.4. 编写获取天气数据的爬虫(Spider)
Spider是用户编写用于从单个网站(或者一些网站)爬取数据的类。
其包含了一个用于下载的初始URL,如何跟进网页中的链接以及如何分析页面中的内容, 提取生成 item 的方法。
为了创建一个Spider,必须继承 scrapy.Spider 类, 且定义以下三个属性:
name: 用于区别Spider。该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。
start_urls: 包含了Spider在启动时进行爬取的url列表。因此,第一个被获取到的页面将是其中之一。后续的URL则从初始的URL获取到的数据中提取。
parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。
我们通过浏览器的查看源码工具先来分析一下需要获取的数据网源代码:
<h4 class="slider_ct_name" id="slider_ct_name">武汉</h4>
...
<div class="blk_fc_c0_scroll" id="blk_fc_c0_scroll" style="width: 1700px;">
<div class="blk_fc_c0_i">
<p class="wt_fc_c0_i_date">01-28</p>
<p class="wt_fc_c0_i_day wt_fc_c0_i_today">今天</p>
<p class="wt_fc_c0_i_icons clearfix">
<img class="icons0_wt png24" src="http://www.sinaimg.cn/dy/weather/main/index14/007/icons_42_yl/w_04_27_00.png" alt="雨夹雪" title="雨夹雪">
<img class="icons0_wt png24" src="http://www.sinaimg.cn/dy/weather/main/index14/007/icons_42_yl/w_04_29_01.png" alt="中雪" title="中雪">
</p>
<p class="wt_fc_c0_i_times">
<span class="wt_fc_c0_i_time">白天</span>
<span class="wt_fc_c0_i_time">夜间</span>
</p>
<p class="wt_fc_c0_i_temp">1°C / -2°C</p>
<p class="wt_fc_c0_i_tip">北风 3~4级</p>
<p class="wt_fc_c0_i_tip">无持续风向 小于3级</p>
</div>
<div class="blk_fc_c0_i">
<p class="wt_fc_c0_i_date">01-29</p>
<p class="wt_fc_c0_i_day ">星期四</p>
<p class="wt_fc_c0_i_icons clearfix">
<img class="icons0_wt png24" src="http://www.sinaimg.cn/dy/weather/main/index14/007/icons_42_yl/w_04_29_00.png" alt="中雪" title="中雪">
<img class="icons0_wt png24" src="http://www.sinaimg.cn/dy/weather/main/index14/007/icons_42_yl/w_07_25_01.png" alt="阴" title="阴">
</p>
<p class="wt_fc_c0_i_times">
<span class="wt_fc_c0_i_time">白天</span>
<span class="wt_fc_c0_i_time">夜间</span>
</p>
<p class="wt_fc_c0_i_temp">1°C / -2°C</p>
<p class="wt_fc_c0_i_tip">无持续风向 小于3级</p>
</div>
...
</div>
我们可以看到:
- 城市名可以通过获取id为slider_ct_name的h4元素获取
- 日期可以通过获取id为blk_fc_c0_scroll下的class为wt_fc_c0_i_date的p元素获取
- 天气描述可以通过获取id为blk_fc_c0_scroll下的class为icons0_wt的img元素获取
- 温度可以通过获取id为blk_fc_c0_scroll下的class为wt_fc_c0_i_temp的p元素获取
因此,我们的Spider代码如下,保存在 weather/spiders 目录下的 localweather.py 文件中:
# -*- coding: utf-8 -*-
import scrapy
from weather.items import WeatherItem
class WeatherSpider(scrapy.Spider):
name = "myweather"
allowed_domains = ["sina.com.cn"]
start_urls = ['http://weather.sina.com.cn']
def parse(self, response):
item = WeatherItem() #把WeatheItem()实例化成item对象
item['city'] = response.xpath('//*[@id="slider_ct_name"]/text()').extract()#//*:选取文档中的所有元素。@:选择属性 /:从节点选取 。extract():提取
tenDay = response.xpath('//*[@id="blk_fc_c0_scroll"]');
item['date'] = tenDay.css('p.wt_fc_c0_i_date::text').extract()
item['dayDesc'] = tenDay.css('img.icons0_wt::attr(title)').extract()
item['dayTemp'] = tenDay.css('p.wt_fc_c0_i_temp::text').extract()
return item
代码中的xpath和css后面括号的内容为选择器,关于xpath和css选择器的内容可参考官方教程:http://doc.scrapy.org/en/0.24/topics/selectors.html
3.5. 运行爬虫,对数据进行验证
到这里为止,我们需要验证一下爬虫是否能正常工作(即能否取到我们想要的数据),验证的方法就是在命令行(重要:在项目的scrapy.cfg文件同级目录运行命令,下同)中运行下面的代码:
$ scrapy crawl myweather -o wea.json
这行命令的意思是,运行名字为 myweather 的爬虫(我们在上一步中定义的),然后把结果以json格式保存在wea.json文件中。命令运行结果如下:
然后,我们查看当前目录下的wea.json文件,正常情况下效果如下:
我们看到,wea.json中已经有数据了,只是数据是以unicode方式编码的。
3.6. 保存爬取到的数据
上面只是把数据保存在json文件中了,如果我们想自己保存在文件或数据库中,如何操作呢?
这里就要用到 Item Pipeline 了,那么 Item Pipeline 是什么呢?
当Item在Spider中被收集之后,它将会被传递到Item Pipeline中,一些组件会按照一定的顺序执行对Item的处理。
每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。
item pipeline的典型应用有:
- 清理HTML数据
- 验证爬取的数据(检查item包含某些字段)
- 查重(并丢弃)
- 将爬取结果保存到文件或数据库中
每个item pipeline组件都需要调用 process_item 方法,这个方法必须返回一个 Item (或任何继承类)对象, 或是抛出 DropItem异常,被丢弃的item将不会被之后的pipeline组件所处理。
我们这里把数据转码后保存在 wea.txt 文本中。
pipelines.py文件在创建项目时已经自动被创建好了,我们在其中加上保存到文件的代码:
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
class WeatherPipeline(object):
def __init__(self):
pass
def process_item(self, item, spider):
with open('wea.txt', 'w+') as file:
city = item['city'][0].encode('utf-8')
file.write('city:' + str(city) + '\n\n')
date = item['date']
desc = item['dayDesc']
dayDesc = desc[1::2]
nightDesc = desc[0::2]
dayTemp = item['dayTemp']
weaitem = zip(date, dayDesc, nightDesc, dayTemp)
for i in range(len(weaitem)):
item = weaitem[i]
d = item[0]
dd = item[1]
nd = item[2]
ta = item[3].split('/')
dt = ta[0]
nt = ta[1]
txt = 'date:{0}\t\tday:{1}({2})\t\tnight:{3}({4})\n\n'.format(
d,
dd.encode('utf-8'),
dt.encode('utf-8'),
nd.encode('utf-8'),
nt.encode('utf-8')
)
file.write(txt)
return item
代码比较简单,都是python比较基础的语法,如果您感觉比较吃力,建议先去学一下python基础课。
3.7. 把 ITEM_PIPELINES 添加到设置中
写好ITEM_PIPELINES后,还有很重要的一步,就是把 ITEM_PIPELINES 添加到设置文件 settings.py 中。
ITEM_PIPELINES = {
'weather.pipelines.WeatherPipeline': 1
}
另外,有些网站对网络爬虫进行了阻止(注:本项目仅从技术角度处理此问题,个人强烈不建议您用爬虫爬取有版权信息的数据),我们可以在设置中修改一下爬虫的 USER_AGENT 和 Referer 信息,增加爬虫请求的时间间隔。
整个 settings.py 文件内容如下:
# -*- coding: utf-8 -*-
# Scrapy settings for weather project
#
# For simplicity, this file contains only the most important settings by
# default. All the other settings are documented here:
#
# http://doc.scrapy.org/en/latest/topics/settings.html
#
BOT_NAME = 'Googlebot'
SPIDER_MODULES = ['weather.spiders']
NEWSPIDER_MODULE = 'weather.spiders'
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'weather (+http://www.yourdomain.com)'
USER_AGENT = 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'
DEFAULT_REQUEST_HEADERS = {
'Referer': 'http://www.weibo.com'
}
ITEM_PIPELINES = {
'weather.pipelines.WeatherPipeline': 1
}
DOWNLOAD_DELAY = 0.5
到现在为止,代码主要部分已经写完了。
3.8. 运行爬虫
在项目的scrapy.cfg同级目录下用下面的命令运行爬虫:
$ scrapy crawl myweather
正常情况下,效果如下:
然后,在当前目录下会多一个 wea.txt 文件,内容如下:
到此我们基于scrapy的天气数据采集就完成了。
四、FAQ
4.1. 结果只出现城市?
scrapy内置的html解析是基于lxml库的,这个库对html的解析的容错性不是很好,通过检查虚拟机中获取到的网页源码,发现有部分标签是不匹配的(地区和浏览器不同取到的源码可能不同),检查结果如图:
所以导致在spider中取到的日期数据(item['date'])为空,然后在pilepine代码中做zip操作后,整个 weaitem 为空,所以最终只有城市数据了。
既然如此,我们换个html代码解析器就可以了,这里建议用 BeautifulSoup (官网:http://www.crummy.com/software/BeautifulSoup/bs4/doc/index.html ),这个解析器有比较好的容错能力,具体用法可以参考上面的文档。
BeautifulSoup安装:
#下载BeautifulSoup
$ wget http://labfile.oss.aliyuncs.com/beautifulsoup4-4.3.2.tar.gz
#解压
$ tar -zxvf beautifulsoup4-4.3.2.tar.gz
#安装
$ cd beautifulsoup4-4.3.2
$ sudo python setup.py install
安装成功后,优化WeatherSpider代码,改进后的代码如下:
# -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
from weather.items import WeatherItem
class WeatherSpider(scrapy.Spider):
name = "myweather"
allowed_domains = ["sina.com.cn"]
start_urls = ['http://weather.sina.com.cn']
def parse(self, response):
html_doc = response.body
#html_doc = html_doc.decode('utf-8')
soup = BeautifulSoup(html_doc)
itemTemp = {}
itemTemp['city'] = soup.find(id='slider_ct_name')
tenDay = soup.find(id='blk_fc_c0_scroll')
itemTemp['date'] = tenDay.findAll("p", {"class": 'wt_fc_c0_i_date'})
itemTemp['dayDesc'] = tenDay.findAll("img", {"class": 'icons0_wt'})
itemTemp['dayTemp'] = tenDay.findAll('p', {"class": 'wt_fc_c0_i_temp'})
item = WeatherItem()
for att in itemTemp:
item[att] = []
if att == 'city':
item[att] = itemTemp.get(att).text
continue
for obj in itemTemp.get(att):
if att == 'dayDesc':
item[att].append(obj['title'])
else:
item[att].append(obj.text)
return item
然后再次运行爬虫:
$ scrapy crawl myweather
然后查看 wea.txt,数据如下:
4.2. 只取到了9天的数据?
如果是晚上运行爬虫,当天的白天天气是没有的(已经过去了),针对这部分建议自己优化。
五、实验代码
本实验的代码可以通过下面这个链接获取:
http://git.shiyanlou.com/shiyanlou/scrapy-weather
基于scrapy爬虫的天气数据采集(python)的更多相关文章
- [Python爬虫] scrapy爬虫系列 <一>.安装及入门介绍
前面介绍了很多Selenium基于自动测试的Python爬虫程序,主要利用它的xpath语句,通过分析网页DOM树结构进行爬取内容,同时可以结合Phantomjs模拟浏览器进行鼠标或键盘操作.但是,更 ...
- 基于Scrapy框架的Python新闻爬虫
概述 该项目是基于Scrapy框架的Python新闻爬虫,能够爬取网易,搜狐,凤凰和澎湃网站上的新闻,将标题,内容,评论,时间等内容整理并保存到本地 详细 代码下载:http://www.demoda ...
- Python分布式爬虫打造搜索引擎完整版-基于Scrapy、Redis、elasticsearch和django打造一个完整的搜索引擎网站
Python分布式爬虫打造搜索引擎 基于Scrapy.Redis.elasticsearch和django打造一个完整的搜索引擎网站 https://github.com/mtianyan/Artic ...
- 爬虫学习之基于Scrapy的爬虫自动登录
###概述 在前面两篇(爬虫学习之基于Scrapy的网络爬虫和爬虫学习之简单的网络爬虫)文章中我们通过两个实际的案例,采用不同的方式进行了内容提取.我们对网络爬虫有了一个比较初级的认识,只要发起请求获 ...
- 基于scrapy框架的爬虫
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中. scrapy 框架 高性能的网络请求 高性能的数据解析 高性能的 ...
- 基于Scrapy的B站爬虫
基于Scrapy的B站爬虫 最近又被叫去做爬虫了,不得不拾起两年前搞的东西. 说起来那时也是突发奇想,想到做一个B站的爬虫,然后用的都是最基本的Python的各种库. 不过确实,实现起来还是有点麻烦的 ...
- Python之Scrapy爬虫框架安装及简单使用
题记:早已听闻python爬虫框架的大名.近些天学习了下其中的Scrapy爬虫框架,将自己理解的跟大家分享.有表述不当之处,望大神们斧正. 一.初窥Scrapy Scrapy是一个为了爬取网站数据,提 ...
- dota玩家与英雄契合度的计算器,python语言scrapy爬虫的使用
首发:个人博客,更新&纠错&回复 演示地址在这里,代码在这里. 一个dota玩家与英雄契合度的计算器(查看效果),包括两部分代码: 1.python的scrapy爬虫,总体思路是pag ...
- 爬虫学习之基于Scrapy的网络爬虫
###概述 在上一篇文章<爬虫学习之一个简单的网络爬虫>中我们对爬虫的概念有了一个初步的认识,并且通过Python的一些第三方库很方便的提取了我们想要的内容,但是通常面对工作当作复杂的需求 ...
随机推荐
- ES6常用知识点小结
ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准. 因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015(简称ES2015).虽然浏览器在不 ...
- VmWareTool安装
- FFT/NTT 总结
本总结主要用于帮助个人理解,讲得不足之处,还请各位看官谅解 FFT 补充知识 \(n\)次单位复根(\(w_n\)): 使得\(z^n=1\)的一类复数,这些复数一共有\(n\)个,它们都分布在复平面 ...
- 【经验随笔】 Tomcat多个APP使用相同名称环境变量导致问题
背景介绍 之前遇到一个问题,在一个tomcat下部署了两个APP,其中一个APP不能正常从底层接口获取数据.如果将两个APP分到不同服务器上的tomcat部署,又都正常了.分析了一下: 远程调试跟代码 ...
- Linux初学者的总结
总算在年前把Linux的一些基本命令学完了,总结一下学到的(比较实用的)东西 我这里用的是Red Hat Enterprise Linux7的社区版本centos7 首先最重要的文件查看命令:ls.d ...
- lambda表达式Expression<Func<Person, bool>> 、Func<Person, bool>区别
前言: 自己通过lambda表达式的封装,将对应的表达式转成字符串的过程中,对lambda表达式有了新的认识 原因: 很多开发者对lambda表达式Expression<Func<Pers ...
- jQuary学习の二の语法
jQuery 语法是通过选取 HTML 元素,并对选取的元素执行某些操作.基础语法: $(selector).action() 美元符号定义 jQuery 选择符(selector)"查询& ...
- 【python学习笔记】9.魔法方法、属性和迭代器
[python学习笔记]9.魔法方法.属性和迭代器 魔法方法:xx, 收尾各有两个下划线的方法 __init__(self): 构造方法,创建对象时候自动执行,可以为其增加参数, 父类构造方法不会被自 ...
- 一年java工作经验的面试题总结(持续更新中)
本人是17年6月份毕业的,3月份出来实习,算起来也是工作一年了吧,金三银四,博主也考虑换一份工作,于是最近面试了几家,总结一下面试中的问题,大家一起交流学习. 第一次面试 ①说下java类的加载 ② ...
- node 自动重启 nodemon
最近在玩node,可是每次修改完js,总要重启下服务,还要杀掉端口,感觉可麻烦了,最近发现nodemon这个东西很好,直接解决了我的烦恼. npm install -g nodemon 以后直接启动n ...