scrapy爬取天气存MySQL_Scrapy实战篇(五)之爬取历史天气数据

本篇文章我们以抓取历史天气数据为例,简单说明数据抓取的两种方式:

1、一般简单或者较小量的数据需求,我们以requests(selenum)+beautiful的方式抓取数据

2、当我们需要的数据量较多时,建议采用scrapy框架进行数据采集,scrapy框架采用异步方式发起请求,数据抓取效率极高。

下面我们以http://www.tianqihoubao.com/lishi/网站数据抓取为例进行进行两种数据抓取得介绍:

1、以request+bs的方式采集天气数据,并以mysql存储数据

思路:

我们要采集的天气数据都在地址 http://www.tianqihoubao.com/lishi/beijing/month/201101.html 中存储,观察url可以发现,url中只有两部分在变化,即城市名称和你年月,而且每年都固定包含12个月份,可以使用 months = list(range(1, 13))构造月份,将城市名称和年份作为变量即可构造出需要采集数据的url列表,遍历列表,请求url,解析response,即可获取数据。

以上是我们采集天气数据的思路,首先我们需要构造url链接。

1 defget_url(cityname,start_year,end_year):2 years =list(range(start_year, end_year))3 months = list(range(1, 13))4 suburl = 'http://www.tianqihoubao.com/lishi/'

5 urllist =[]6 for year inyears:7 for month inmonths:8 if month < 10:9 url = suburl + cityname + '/month/'+ str(year) + (str(0) + str(month)) + '.html'

10 else:11 url = suburl + cityname + '/month/' + str(year) + str(month) + '.html'

12 urllist.append(url.strip())13 return urllist

通过以上函数,可以得到需要抓取的url列表。

可以看到,我们在上面使用了cityname,而cityname就是我们需要抓取的城市的城市名称,需要我们手工构造,假设我们已经构造了城市名称的列表,存储在mysql数据库中,我们需要查询数据库获取城市名称,遍历它,将城市名称和开始年份,结束年份,给上面的函数。

1 defget_cityid(db_conn,db_cur,url):2 suburl = url.split('/')3 sql = 'select cityid from city where cityname = %s'

4 db_cur.execute(sql,suburl[4])5 cityid =db_cur.fetchone()6 idlist =list(cityid)7 return idlist[0]

有了城市代码,开始和结束年份,生成了url列表,接下来当然就是请求地址,解析返回的html代码了,此处我们以bs解析网页源代码,代码如下:

1 defparse_html_bs(db_conn,db_cur,url):2 proxy =get_proxy()3 proxies ={4 'http': 'http://' +proxy,5 'https': 'https://' +proxy,6 }7 headers ={8 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',9 'Connection': 'close'

10 }11

12 #获取天气数据的html网页源代码

13 weather_data = requests.get(url=url, headers=headers,proxies =proxies).text14 weather_data_new =(weather_data.replace('\n','').replace('\r','').replace(' ',''))15 soup = BeautifulSoup(weather_data_new,'lxml')16 table = soup.find_all(['td'])17 #获取城市id

18 cityid =get_cityid(db_conn, db_cur, url)19 listall =[]20 for t inlist(table):21 ts =t.string22 listall.append(ts)23 n= 4

24 sublist = [listall[i:i+n] for i inrange(0,len(listall),n)]25 sublist.remove(sublist[0])26 flist =[]27 #将列表元素中的最高和最低气温拆分,方便后续数据分析,并插入城市代码

28 for sub insublist:29 if sub ==sublist[0]:30 pass

31 sub2 = sub[2].split('/')32 sub.remove(sub[2])33 sub.insert(2, sub2[0])34 sub.insert(3, sub2[1])35 sub.insert(0, cityid) #插入城市代码

36 flist.append(sub)37 return flist

最后我们在主函数中遍历上面的列表,并将解析出来的结果存储到mysql数据库。

1 if __name__ == '__main__':2 citylist =get_cityname(db_conn,db_cur)3 for city incitylist:4 urllist = get_url(city,2016,2019)5 for url inurllist:6 time.sleep(1)7 flist =parse_html_bs(db_conn, db_cur, url)8 for li inflist:9 tool.dyn_insert_sql('weather',tuple(li),db_conn,db_cur)10 time.sleep(1)

以上我们便完成了以requests+bs方式抓取历史天气数据,并以mysql存储的程序代码,完成代码见:https://gitee.com/liangxinbin/Scrpay/blob/master/weatherData.py

2、用scrapy框架采集天气数据,并以mongo存储数据

1)定义我们需要抓取的数据结构,修改框架中的items.py文件

1 classWeatherItem(scrapy.Item):2 #define the fields for your item here like:

3 #name = scrapy.Field()

4 cityname =Field() #城市名称5 data =Field()    #日期6 tq =Field()     #天气7 maxtemp=Field()   #最高温度8 mintemp=Field()   #最低温度9 fengli=Field()    #风力

2)修改下载器中间件,随机获取user-agent,ip地址

1 classRandomUserAgentMiddleware():2 def __init__(self,UA):3 self.user_agents =UA4

5 @classmethod6 deffrom_crawler(cls, crawler):7 return cls(UA = crawler.settings.get('MY_USER_AGENT')) #MY_USER_AGENT在settings文件中配置,通过类方法获取8

9 defprocess_request(self,request,spider):10 request.headers['User-Agent'] =random.choice(self.user_agents) #随机获取USER_AGENT11

12 defprocess_response(self,request, response, spider):13 returnresponse14

15

16 classProxyMiddleware():17 def __init__(self):18 ipproxy = requests.get('http://localhost:5000/random/') #此地址为从代理池中随机获取可用代理19 self.random_ip = 'http://' +ipproxy.text20

21 defprocess_request(self,request,spider):22 print(self.random_ip)23 request.meta['proxy'] =self.random_ip24

25 defprocess_response(self,request, response, spider):26 return response

3)修改pipeline文件,处理返回的item,处理蜘蛛文件返回的item

1 importpymongo2

3 classMongoPipeline(object):4

5 def __init__(self,mongo_url,mongo_db,collection):6 self.mongo_url =mongo_url7 self.mongo_db =mongo_db8 self.collection =collection9

10 @classmethod

14 deffrom_crawler(cls,crawler):15 returncls(16 mongo_url=crawler.settings.get('MONGO_URL'), #MONGO_URL,MONGO_DB,COLLECTION在settings文件中配置,通过类方法获取数据17 mongo_db = crawler.settings.get('MONGO_DB'),18 collection = crawler.settings.get('COLLECTION')19 )20

21 defopen_spider(self,spider):22 self.client =pymongo.MongoClient(self.mongo_url)23 self.db =self.client[self.mongo_db]24

25 defprocess_item(self,item, spider):26 #name = item.__class__.collection

27 name =self.collection28 self.db[name].insert(dict(item)) #将数据插入到mongodb数据库。29 returnitem30

31 defclose_spider(self,spider):32 self.client.close()

4)最后也是最重要的,编写蜘蛛文件解析数据,先上代码,在解释

1 #-*- coding: utf-8 -*-

2 importscrapy3 from bs4 importBeautifulSoup4 from scrapy importRequest5 from lxml importetree6 from scrapymodel.items importWeatherItem7

8

9 classWeatherSpider(scrapy.Spider):10 name = 'weather' #蜘蛛的名称,在整个项目中必须唯一

11 #allowed_domains = ['tianqihoubao']

12 start_urls = ['http://www.tianqihoubao.com/lishi/'] #起始链接,用这个链接作为开始,爬取数据,它的返回数据默认返回给parse来解析。13

14

15 #解析http://www.tianqihoubao.com/lishi/网页,提取连接形式http://www.tianqihoubao.com/lishi/beijing.html

16 defparse(self, response):17 soup = BeautifulSoup(response.text, 'lxml')18 citylists = soup.find_all(name='div', class_='citychk')19 for citys incitylists:20 for city in citys.find_all(name='dd'):21 url = 'http://www.tianqihoubao.com' + city.a['href']22 yield Request(url=url,callback =self.parse_citylist) #返回Request对象,作为新的url由框架进行调度请求,返回的response有回调函数parse_citylist进行解析23

24 #解析http://www.tianqihoubao.com/lishi/beijing.html网页,提取链接形式为http://www.tianqihoubao.com/lishi/tianjin/month/201811.html

25 defparse_citylist(self,response):26 soup = BeautifulSoup(response.text, 'lxml')27 monthlist = soup.find_all(name='div', class_='wdetail')28 for months inmonthlist:29 for month in months.find_all(name='li'):30 if month.text.endswith("季度:"):31 continue

32 else:33 url = month.a['href']34 url = 'http://www.tianqihoubao.com' +url35 yield Request(url= url,callback =self.parse_weather) #返回Request对象,作为新的url由框架进行调度请求,返回的response由parse_weather进行解析36

37 #以xpath解析网页数据;

38 defparse_weather(self,response): #解析网页数据,返回数据给pipeline处理39 #获取城市名称

40 url =response.url41 cityname = url.split('/')[4]42

43 weather_html =etree.HTML(response.text)44 table = weather_html.xpath('//table//tr//td//text()')45 #获取所有日期相关的数据,存储在列表中

46 listall =[]47 for t intable:48 if t.strip() == '':49 continue

50 #替换元素中的空格和\r\n

51 t1 = t.replace(' ', '')52 t2 = t1.replace('\r\n', '')53 listall.append(t2.strip())54 #对提取到的列表数据进行拆分,将一个月的天气数据拆分成每天的天气情况,方便数据插入数据库

55 n = 4

56 sublist = [listall[i:i + n] for i inrange(0, len(listall), n)]57 #删除表头第一行

58 sublist.remove(sublist[0])59 #将列表元素中的最高和最低气温拆分,方便后续数据分析,并插入城市代码

60

61 for sub insublist:62 if sub ==sublist[0]:63 pass

64 sub2 = sub[2].split('/')65 sub.remove(sub[2])66 sub.insert(2, sub2[0])67 sub.insert(3, sub2[1])68 sub.insert(0, cityname)69

70 Weather = WeatherItem() #使用items中定义的数据结构71

72 Weather['cityname'] =sub[0]73 Weather['data'] = sub[1]74 Weather['tq'] = sub[2]75 Weather['maxtemp'] = sub[3]76 Weather['mintemp'] = sub[4]77 Weather['fengli'] = sub[5]78 yield Weather

运行项目,即可获取数据,至此,我们完成了天气数据的抓取项目。

项目完整代码:

https://gitee.com/liangxinbin/Scrpay/tree/master/scrapymodel

9c589b77aa24ccaa4fae40ec55c1f74a.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/508140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 第二天数据_MySQL入门第二天------数据库操作

一、基本命令1、启动服务器cmdnet start [服务器名称]net start mysql572、停止服务器cmdnet stop [服务器名称]net stop mysql573、链接数据库mysql -u 用户名 -p 登录密码mysql -u root -p4、退出登录quitexit\q5、查看版本(连接后执行)select version();6、查看当前时间(连接…

如何打开java_怎样运行java

怎样运行java? 第一步:下载并安装JDK 6.0,安装路劲为: C:\java\jdk1.6 . 第二步:对“我的电脑”按右键,选“属性”,在“系统属性”窗口中选“高级”标签,再按“环境变量”按钮,弹出一个“环境变量”的窗口,在系统变量中新建一个变量,变量名为“JAVA_HOME“,变量值为…

java 字符串匹配_多模字符串匹配算法原理及Java实现代码

多模字符串匹配算法在这里指的是在一个字符串中寻找多个模式字符字串的问题。一般来说&#xff0c;给出一个长字符串和很多短模式字符串&#xff0c;如何最快最省的求出哪些模式字符串出现在长字符串中是我们所要思考的。该算法广泛应用于关键字过滤、入侵检测、病毒检测、分词…

java http 异步请求框架_GitHub - huangdali/MyHttpUtils: 一个非常好用的异步网络请求框架...

轻量级网络请求框架MyHttputils 一、前言本版代码大换血&#xff0c;使用了策略模式和构造模式来组织代码&#xff0c;增加了更加人性化的请求构造&#xff0c;代码质量提高、效率显著提升。(但是使用风格基本没变哦)2.0.2版本的基本的用法在《android网络请求框架》一个轻量级…

mysql 推送微信公众号_10分钟完成微信公众号第三方平台全网发布

背景&#xff1a;在微信公众平台配置服务器URL时&#xff0c;使用了新浪云SAE自带的二级域名&#xff0c;提交时出现一个安全风险的警告&#xff0c;网上查了下&#xff0c;许多服务平台和团队也遇到同样的问题。经过一番研究 …为什么会有安全风险的警告&#xff1f;微信公众平…

java排序算法原理_排序算法原理与实现(java)

排序算法原理与实现(java) Java程序员必知的8大排序 [来源&#xff1a;本站 | 日期&#xff1a;2012年12月24日 | 浏览173 次] 字体:[大 中 小] 8种排序之间的关系: 1&#xff0c; 直接插入排序 (1)基本思想&#xff1a;在要排序的一组数中&#xff0c;假设前面(n-1)[n>2] 个…

ios django 连接mysql_Django---Django连接Mysql数据库

前面介绍了Django平台的数据交互&#xff0c;这些数据都是在本地存放着&#xff0c;修改内容或者重新启动服务&#xff0c;数据就消失了&#xff0c;如果我们把数据存放在数据库中&#xff0c;不就保存了吗&#xff1f;Django数据库Django中自带的也有数据库(sqlite3)&#xff…

java xmpp openfire_XMPP协议学习笔记三(Openfire服务器端搭建开发环境)

在了解了XMPP的基本结构和一些概念之后&#xff0c;我们暂时告别枯燥的理论学习&#xff0c;来动手搭建一下OpenfireSpark的开发环境&#xff0c;实际感受一下搭建整套IM通讯系统的过程。开发环境&#xff1a;windows XP sp3&#xff0c;Eclipse3.6.1&#xff0c;jdk1.6.0_24&a…

java接口经常变动前端怎么办_Java进程故障排查(CPU资源占用高,接口响应超时,功能接口停滞等)...

故障分析# 导致系统不可用情况(频率较大)&#xff1a;1)代码中某个位置读取数据量较大&#xff0c;导致系统内存耗尽&#xff0c;进而出现Full GC次数过多&#xff0c;系统缓慢&#xff1b;2)代码中有比较消耗CPU的操作&#xff0c;导致CPU过高&#xff0c;系统运行缓慢&#x…

使用java实现面向对象编程第二章_java面向对象编程——第二章 java基础语法

第二章java基础语法1、java关键字abstractbooleanbreakbytecasecatchcharclassconstcontinuedefaultdodoubleelseextendsassertfinalfinallyfloatforgotoifimplementsimportinstanceofintinterfacelongnativenewstrictfppackageprivateprotectedpublicreturnshortstaticsupersw…

用java实现楼层导航_JS实现网站楼层导航效果代码实例

壹 ❀ 引言对于楼层导航而言&#xff0c;还有个重要的功能就是&#xff0c;随着滚动条滚动&#xff0c;达到某层时得同步点亮楼层导航的小图片。由于我前面也说了不打算使用JQ&#xff0c;所以想着用JS去实现它&#xff0c;实现并不难&#xff0c;主要得弄清滚动满足怎样的条件…

费尔马小定理素数java_利用费马小定理判断素数

今天听了ljss神犇的数论课&#xff0c;顿时感觉————我真的是太弱啦&#xff01;我只能稍微写一下我能听懂的部分orz那么这就是今天我为数不多能听懂一点的之一......QAQ首先先介绍今天的主角&#xff1a;费马小定理————转自维基百科没看懂的话我稍微解释一下&#xff0…

java aspectj_AspectJ基本用法

AOP虽然是方法论&#xff0c;但就好像OOP中的Java一样&#xff0c;一些先行者也开发了一套语言来支持AOP。目前用得比较火的就是AspectJ了&#xff0c;它是一种几乎和Java完全一样的语言&#xff0c;而且完全兼容Java(AspectJ应该就是一种扩展Java&#xff0c;但它不是像Groovy…

php json to object,PHP JSON_FORCE_OBJECT函数实现强转对象

JSON_FORCE_OBJECT在多级数组中&#xff0c;JSON_FORCE_OBJECT会将所有嵌套数值数组编码为对象。如果你只关注第一级数组(例如&#xff0c;使其适合作为MySQL JSON列)&#xff0c;那么可以将第一级数组强制转换为对象&#xff0c;例如&#xff1a;$ json json_encode((object)…

php推送示例wordpress,给WordPress的编辑后台添加提示框的代码实例分享

WordPress 3.5 新添加了一个提示框功能&#xff0c;可以创建一个提示框&#xff0c;然后指向任何元素&#xff0c;比如下边的例子&#xff1a;本文就来教你怎么创建一个这样的提示框。首先需要添加提示框的脚本&#xff0c;这样才能使用提示框的 JS 方法。//挂载提示框脚本func…

jmeter php网站,jmeter实战之phpwind随机回帖/发帖

关键词&#xff1a;jmeter phpwind 性能测试一、性能需求1)性能需求&#xff1a;30min内&#xff0c;phpwind随机回帖/发帖&#xff0c;观察服务器性能的表现。2)需求分析&#xff1a;2.1 核心业务论坛系统的核心业务主要是登录、看帖、发帖、回帖&#xff0c;业务建模时应考虑…

php7改进,关注一下:PHP 7.3.7 正式发布 改进、修复的地方不少哦

PHP 7.3.7正式发布了。PHP(PHP&#xff1a;Hypertext Preprocessor)是一种在电脑上执行的脚本语言&#xff0c;主要是用途在于处理动态网页&#xff0c;也包含了命令列执行接口(command line interface)&#xff0c;或者产生图形使用者接口(GUI)程式。版本主要还是修复 bug&…

php jwt token刷新方案,laravel JWT自动刷新 自定义验证器

在前面的文章中&#xff0c;我们引入了JWT的验证方式&#xff0c;但是在前面并没有做过多的处理&#xff0c;只是用JWT生成了一个token&#xff0c;那么今天来就解决后续问题为了保证用户信息的安全&#xff0c; 我们的生成的JWT不可能一直有效&#xff0c;我们在配置文件里边配…

2019java形势,2019Java开发还有哪些发展

相信已经有不少人在心里考虑着春节之后转行新工作了吧&#xff0c;而在众多行业中IT行业&#xff0c;特别是Java开发、Java程序员等岗位相信是很多人的首选。谁让现在程序员薪资这么高呢&#xff0c;但是现在互联网发展迅速&#xff0c;各类编程语言层出不穷&#xff0c;比如py…

mysql允许两个用户远程连接,配置MySQL服务允许用户远程连接

默认情况下&#xff0c;mysql只允许本地登录&#xff0c;如果要开启远程连接&#xff0c;则需要修改/etc/mysql/my.conf文件。一、修改/etc/mysql/my.conf找到bind-address 127.0.0.1这一行改为bind-address 0.0.0.0即可二、为需要远程登录的用户赋予权限1、新建用户远程连接…