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

  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. .NET:bin 与 obj,Debug 与 Release ,区别与选择

    bin 与 obj bin 目录:用来存放编译的结果. ( bin是二进制binrary的英文缩写,因为最初C编译的程序文件都是二进制文件 ) 编译的结果,有 Debug 和 Release 两个版本 ...

  2. [hdu P4081] Qin Shi Huang’s National Road System

    [hdu P4081] Qin Shi Huang’s National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Li ...

  3. .net core 使用 ef core

    第一步: 创建一个.net core console app. 第二步:安装EFCore package 和  design(以前vs是有EF项目模板的,core版本现在没有,所有安装这个工具来创建M ...

  4. redis列表操作基本命令

    RPUSH:从列表尾部插入一个元素,RPOP:返回列表最后一个元素并从列表删除LPUSH:从列表头部插入一个元素,LPOP:返回列表第一个元素并从列表删除(没看到命名的介绍,个人理解R就是right, ...

  5. Linux Shell基础(下)

    Linux Shell基础(下) 目录 一.shell特殊符号cut命令 二.cut.sort.wc.uniq命令 三.tee.tr.split命令 四.简易审计系统 五.fork, exec, so ...

  6. Redis在Linux系统下的安装和启动

    详情可参见:https://blog.csdn.net/q1035331653/article/details/79077260 开机自启脚本参见:https://www.cnblogs.com/si ...

  7. 前端开发【第一篇: HTML】

    HTML初识  1.什么是HTML? HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,他是一种制作万维网页面标准语言(标记).  2.网页的组成 我们平时 ...

  8. L332 NBA: Dwyane Wade and Dirk Nowitzki Say Emotional Goodbyes

    Two games in the NBA ended amid emotional scenes on Tuesday as legends at separate teams marked thei ...

  9. asp.net button控件 使用JS的 disabled

     今天想用JS禁用asp.net的button控件,查了好久,都是一行代码....      document.getElementById("Button1").disabled ...

  10. Tex_Err:缺失wlscirep.cls

    使用期刊模板编译时,需要'.cls'一类格式文件支持.从Overleaf上直接Copy代码到本地,发现自己的tex运行时会报错: ! LaTeX Error: File `wlscirep.cls' ...