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

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

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

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

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

  思路:

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

  

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

  

 def get_url(cityname,start_year,end_year):
years = list(range(start_year, end_year))
months = list(range(1, 13))
suburl = 'http://www.tianqihoubao.com/lishi/'
urllist = []
for year in years:
for month in months:
if month < 10:
url = suburl + cityname + '/month/'+ str(year) + (str(0) + str(month)) + '.html'
else:
url = suburl + cityname + '/month/' + str(year) + str(month) + '.html'
urllist.append(url.strip())
return urllist

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

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

 def get_cityid(db_conn,db_cur,url):
suburl = url.split('/')
sql = 'select cityid from city where cityname = %s '
db_cur.execute(sql,suburl[4])
cityid = db_cur.fetchone()
idlist = list(cityid)
return idlist[0]

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

 def parse_html_bs(db_conn,db_cur,url):
proxy = get_proxy()
proxies = {
'http': 'http://' + proxy,
'https': 'https://' + proxy,
}
headers = {
'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',
'Connection': 'close'
} # 获取天气数据的html网页源代码
weather_data = requests.get(url=url, headers=headers,proxies = proxies).text
weather_data_new =(weather_data.replace('\n','').replace('\r','').replace(' ',''))
soup = BeautifulSoup(weather_data_new,'lxml')
table = soup.find_all(['td'])
# 获取城市id
cityid = get_cityid(db_conn, db_cur, url)
listall = []
for t in list(table):
ts = t.string
listall.append(ts)
n= 4
sublist = [listall[i:i+n] for i in range(0,len(listall),n)]
sublist.remove(sublist[0])
flist = []
# 将列表元素中的最高和最低气温拆分,方便后续数据分析,并插入城市代码
for sub in sublist:
if sub == sublist[0]:
pass
sub2 = sub[2].split('/')
sub.remove(sub[2])
sub.insert(2, sub2[0])
sub.insert(3, sub2[1])
sub.insert(0, cityid) # 插入城市代码
flist.append(sub)
return flist

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

 if __name__ == '__main__':
citylist = get_cityname(db_conn,db_cur)
for city in citylist:
urllist = get_url(city,2016,2019)
for url in urllist:
time.sleep(1)
flist = parse_html_bs(db_conn, db_cur, url)
for li in flist:
tool.dyn_insert_sql('weather',tuple(li),db_conn,db_cur)
time.sleep(1)

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

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

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

 class WeatherItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
cityname = Field() #城市名称
data = Field()    #日期
tq = Field()     #天气
maxtemp=Field()   #最高温度
mintemp=Field()   #最低温度
fengli=Field()    #风力

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

 class RandomUserAgentMiddleware():
def __init__(self,UA):
self.user_agents = UA @classmethod
def from_crawler(cls, crawler):
return cls(UA = crawler.settings.get('MY_USER_AGENT')) #MY_USER_AGENT在settings文件中配置,通过类方法获取 def process_request(self,request,spider):
request.headers['User-Agent'] = random.choice(self.user_agents) #随机获取USER_AGENT def process_response(self,request, response, spider):
return response class ProxyMiddleware():
def __init__(self):
ipproxy = requests.get('http://localhost:5000/random/') #此地址为从代理池中随机获取可用代理
self.random_ip = 'http://' + ipproxy.text def process_request(self,request,spider):
print(self.random_ip)
request.meta['proxy'] = self.random_ip def process_response(self,request, response, spider):
return response

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

  

 import pymongo

 class MongoPipeline(object):

     def __init__(self,mongo_url,mongo_db,collection):
self.mongo_url = mongo_url
self.mongo_db = mongo_db
self.collection = collection @classmethod
def from_crawler(cls,crawler):
return cls(
mongo_url=crawler.settings.get('MONGO_URL'), #MONGO_URL,MONGO_DB,COLLECTION在settings文件中配置,通过类方法获取数据
mongo_db = crawler.settings.get('MONGO_DB'),
collection = crawler.settings.get('COLLECTION')
) def open_spider(self,spider):
self.client = pymongo.MongoClient(self.mongo_url)
self.db = self.client[self.mongo_db] def process_item(self,item, spider):
# name = item.__class__.collection
name = self.collection
self.db[name].insert(dict(item)) #将数据插入到mongodb数据库。
return item def close_spider(self,spider):
self.client.close()

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

 # -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
from scrapy import Request
from lxml import etree
from scrapymodel.items import WeatherItem class WeatherSpider(scrapy.Spider):
name = 'weather' #蜘蛛的名称,在整个项目中必须唯一
# allowed_domains = ['tianqihoubao']
start_urls = ['http://www.tianqihoubao.com/lishi/'] #起始链接,用这个链接作为开始,爬取数据,它的返回数据默认返回给parse来解析。 #解析http://www.tianqihoubao.com/lishi/网页,提取连接形式http://www.tianqihoubao.com/lishi/beijing.html
def parse(self, response):
soup = BeautifulSoup(response.text, 'lxml')
citylists = soup.find_all(name='div', class_='citychk')
for citys in citylists:
for city in citys.find_all(name='dd'):
url = 'http://www.tianqihoubao.com' + city.a['href']
yield Request(url=url,callback = self.parse_citylist) #返回Request对象,作为新的url由框架进行调度请求,返回的response有回调函数parse_citylist进行解析 #解析http://www.tianqihoubao.com/lishi/beijing.html网页,提取链接形式为http://www.tianqihoubao.com/lishi/tianjin/month/201811.html
def parse_citylist(self,response):
soup = BeautifulSoup(response.text, 'lxml')
monthlist = soup.find_all(name='div', class_='wdetail')
for months in monthlist:
for month in months.find_all(name='li'):
if month.text.endswith("季度:"):
continue
else:
url = month.a['href']
url = 'http://www.tianqihoubao.com' + url
yield Request(url= url,callback = self.parse_weather) #返回Request对象,作为新的url由框架进行调度请求,返回的response由parse_weather进行解析 # 以xpath解析网页数据;
def parse_weather(self,response): #解析网页数据,返回数据给pipeline处理
# 获取城市名称
url = response.url
cityname = url.split('/')[4] weather_html = etree.HTML(response.text)
table = weather_html.xpath('//table//tr//td//text()')
# 获取所有日期相关的数据,存储在列表中
listall = []
for t in table:
if t.strip() == '':
continue
# 替换元素中的空格和\r\n
t1 = t.replace(' ', '')
t2 = t1.replace('\r\n', '')
listall.append(t2.strip())
# 对提取到的列表数据进行拆分,将一个月的天气数据拆分成每天的天气情况,方便数据插入数据库
n = 4
sublist = [listall[i:i + n] for i in range(0, len(listall), n)]
# 删除表头第一行
sublist.remove(sublist[0])
# 将列表元素中的最高和最低气温拆分,方便后续数据分析,并插入城市代码 for sub in sublist:
if sub == sublist[0]:
pass
sub2 = sub[2].split('/')
sub.remove(sub[2])
sub.insert(2, sub2[0])
sub.insert(3, sub2[1])
sub.insert(0, cityname) Weather = WeatherItem() #使用items中定义的数据结构 Weather['cityname'] = sub[0]
Weather['data'] = sub[1]
Weather['tq'] = sub[2]
Weather['maxtemp'] = sub[3]
Weather['mintemp'] = sub[4]
Weather['fengli'] = sub[5]
yield Weather

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

项目完整代码:

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

Scrapy实战篇(五)之爬取历史天气数据的更多相关文章

  1. Scrapy 通过登录的方式爬取豆瓣影评数据

    Scrapy 通过登录的方式爬取豆瓣影评数据 爬虫 Scrapy 豆瓣 Fly 由于需要爬取影评数据在来做分析,就选择了豆瓣影评来抓取数据,工具使用的是Scrapy工具来实现.scrapy工具使用起来 ...

  2. PHP爬取历史天气

    PHP爬取历史天气 PHP作为宇宙第一语言,爬虫也是非常方便,这里爬取的是从天气网获得中国城市历史天气统计结果. 程序架构 main.php <?php include_once(". ...

  3. python 爬取历史天气

    python 爬取历史天气 官网:http://lishi.tianqi.com/luozhuangqu/201802.html # encoding:utf-8 import requests fr ...

  4. (3)分布式下的爬虫Scrapy应该如何做-递归爬取方式,数据输出方式以及数据库链接

    放假这段时间好好的思考了一下关于Scrapy的一些常用操作,主要解决了三个问题: 1.如何连续爬取 2.数据输出方式 3.数据库链接 一,如何连续爬取: 思考:要达到连续爬取,逻辑上无非从以下的方向着 ...

  5. 爬虫(十七):Scrapy框架(四) 对接selenium爬取京东商品数据

    1. Scrapy对接Selenium Scrapy抓取页面的方式和requests库类似,都是直接模拟HTTP请求,而Scrapy也不能抓取JavaScript动态谊染的页面.在前面的博客中抓取Ja ...

  6. PyQuery爬取历史天气信息

    1.准备工作: 网址:https://lishi.tianqi.com/xian/index.html 爬虫类库:PyQuery,requests 2.网页分析: 红线部分可更改为需要爬取的城市名,如 ...

  7. 爬虫再探实战(五)———爬取APP数据——超级课程表【四】——情感分析

    仔细看的话,会发现之前的词频分析并没有什么卵用...文本分析真正的大哥是NLP,不过,这个坑太大,小白不大敢跳...不过还是忍不住在坑边上往下瞅瞅2333. 言归正传,今天刚了解到boson公司有py ...

  8. Scrapy实战篇(七)之爬取爱基金网站基金业绩数据

    本篇我们以scrapy+selelum的方式来爬取爱基金网站(http://fund.10jqka.com.cn/datacenter/jz/)的基金业绩数据. 思路:我们以http://fund.1 ...

  9. python爬虫实战(六)--------新浪微博(爬取微博帐号所发内容,不爬取历史内容)

    相关代码已经修改调试成功----2017-4-13 详情代码请移步我的github:https://github.com/pujinxiao/sina_spider 一.说明 1.目标网址:新浪微博 ...

随机推荐

  1. rest_framework 之视图

    1. 继承ModelSerilizer,直接指定要序列化的表模型 MySerializers.py from app import models # 继承ModelSerilizer,直接指定要序列化 ...

  2. [Codeforces440D]Berland Federalization

    Problem 给你一棵树,最少删掉哪些边,能使得余下的至少有1个大小刚好为k的残树. 1 ≤ k ≤ n ≤ 400 Solution 用f[i][j]表示以i为根有j个节点的最少删边数量 因为此题 ...

  3. 【转】python 中NumPy和Pandas工具包中的函数使用笔记(方便自己查找)

    二.常用库 1.NumPy NumPy是高性能科学计算和数据分析的基础包.部分功能如下: ndarray, 具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组. 用于对整组数据进行快速运算的标准 ...

  4. jQuery键盘敲击事件,换键的话换键码就可以

    $("body").keyup(function () { if (event.which == 13){ $("#Btn_login").trigger(&q ...

  5. 浏览器输入URL按回车后都经历了什么?

    在浏览器上输入一个URL,按回车后,这个过程发生了什么? 1.首先,浏览器地址栏输入了URL,先解析URL,检测URL地址是否合法 2.浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直 ...

  6. springcloud学习计划

    后续参考学习spring cloud https://blog.csdn.net/forezp/article/details/70148833 https://github.com/forezp/S ...

  7. pycharm的中文汉化

    下载pycharm软件 然后通过下面的网站进行激活: http://idea.lanyus.com/ 激活好后下载汉化包:链接:http://pan.baidu.com/s/1i5zaGgX 密码:g ...

  8. 学号 20175223 《Java程序设计》第2周学习总结

    学号 20175223 <Java程序设计>第2周学习总结 教材学习内容总结 第二章要点: 要点1:标识符与关键字 要点2:基本数据类型:逻辑类型boolean,整数类型int|byte| ...

  9. 入门项目 A5-1 interface-bank 第三方接口1

    from db import db_handler # 提现接口 def withdraw_interface(name, money): # 定义提现接口,传入name与money参数 user_d ...

  10. Reactor

    Flux和Mono Flux和Mono是Reactor中的两个基本概念.Flux表示的是包含0到N个元素的异步序列.在该序列中可以包含三种不同类型的消息通知:正常的包含元素的消息,序列结束的消息和序列 ...