Python 爬取全国天气

来源

来自中国天气网
在这里插入图片描述

成果

在这里插入图片描述
在这里插入图片描述

爬取所有城市的URL

一个城市对应一个URL,所以需要获得所有城市的URL并保存到本地文件。

运行该步骤的时间会很长,但是一劳永逸,只需要跑一遍。

也可以选择下载我提供的文件,我把该文件放到百度云了
链接: https://pan.baidu.com/s/1Mxok17-YhXP_OdjVHdyuYQ
密码: enpc

import requests
from bs4 import BeautifulSoup
from WebWorm.RandomHeader import getRandomHeader
import re

"""
1、参数:url
2、主要功能:根据url解析页面
3、返回值:html页面内容
"""


def parse(url):
    # 设置随机头
    headers = {"user-agent": getRandomHeader()}
    # 请求URL
    request = requests.get(url, headers=headers)
    # 设置编码
    request.encoding = 'utf-8'
    # 请求到的内容
    html = request.text
    # 返回请求到的内容
    return html


"""
1、参数:
nameAndUrl是存放地区名称和URL地址的数组
exceptionUrl是发生异常的URL
2、主要功能:获取直辖市的名称和对应的URL
3、返回值:nameAndUrl、exceptionUrl
"""


def zhiXiaShi(nameAndUrl, exceptionUrl):
    # 直辖市 101是中国  后两位xx是直辖市的编码01-04  后四位xxxx是直辖市的区号  每次递增100
    # 例如
    # http://www.weather.com.cn/weather/101010200.shtml 北京海淀
    # http://www.weather.com.cn/weather/101010300.shtml 北京朝阳

    # url的前半部分
    url = 'http://www.weather.com.cn/weather/101'
    for i in range(1, 5):
        # 直辖市编号
        zhiXiaShi = str(i).zfill(2)
        for k in range(100, 10000, 100):
            # 直辖市区号
            zhiXiaShiQu = str(k).zfill(4)
            # 拼接URL
            urlTemp = url + zhiXiaShi + zhiXiaShiQu + '.shtml'
            # 如果解析过程中发生了错误异常,把这个URL加入数组,继续下次循环,因为有时网络波动会导致访问失败。
            # 只要该URL发生了异常,就加入异常数组,等待后期处理,不会妨碍后面的URL继续执行。
            try:
                # 解析URL
                html = parse(urlTemp)
                # 如果URL是无效的
                if html.__eq__('<!-- empty -->'):
                    # 退出循环
                    break
                else:
                    # 获取该URL的名称
                    name = getName(html)
                    # 把地区名和URL同时加入数组,空格作为分隔符
                    nameAndUrl.append(name + ' ' + urlTemp)
                    print('获取' + name + '---成功')
            except:
                # 把URL加入异常数组
                exceptionUrl.append(urlTemp)
    # 返回数组
    return nameAndUrl, exceptionUrl


"""
1、参数:
nameAndUrl是存放地区名称和URL地址的数组
exceptionUrl是发生异常的URL
2、主要功能:获取省的名称和对应的URL
3、返回值:nameAndUrl、exceptionUrl
"""


def sheng(nameAndUrl, exceptionUrl):
    # 省  101是中国  后两位xx是省05-34  后两位xx是市  后两位xx是县  每次递增1
    # 例如
    # http://www.weather.com.cn/weather/101100203.shtml 山西大同大同县
    # http://www.weather.com.cn/weather/101100204.shtml 山西大同天镇

    # url的前半部分
    url = 'http://www.weather.com.cn/weather/101'
    for i in range(5, 35):
        # 省编号
        sheng = str(i).zfill(2)
        for q in range(1, 100, 1):
            # 市编号
            shi = str(q).zfill(2)
            # 如果解析过程中发生了错误异常,把这个URL记录下来,继续下次循环
            try:
                # 如果连01都没有,那么这个省就结束了
                html = parse(url + sheng + shi + '01.shtml')
                if html.__eq__('<!-- empty -->'):
                    # 退出循环
                    break
            except:
                # 把URL加入异常数组
                exceptionUrl.append(url + sheng + shi + '01.shtml')
            for f in range(1, 100, 1):
                # 县编号
                xian = str(f).zfill(2)
                # 拼接URL
                urlTemp = url + sheng + shi + xian + '.shtml'
                # 如果解析过程中发生了错误异常,把这个URL记录下来,继续下次循环
                try:
                    # 解析URL
                    html = parse(urlTemp)
                    # 如果URL是无效的
                    if html.__eq__('<!-- empty -->'):
                        # 退出循环
                        break
                    else:
                        # 获取该URL的名称
                        name = getName(html)
                        # 名称是全国开头的,才是我们需要的URL
                        if re.match('^全国.*', name):
                            # 把地区名和URL同时加入数组,空格作为分隔符
                            nameAndUrl.append(name + ' ' + urlTemp)
                            print('获取' + name + '---成功')
                except:
                    # 把URL加入异常数组
                    exceptionUrl.append(urlTemp)
    # 返回数组
    return nameAndUrl, exceptionUrl


"""
1、参数:
nameAndUrl是存放地区名称和URL地址的数组
exceptionUrl是发生异常的URL
2、主要功能:
重新运行异常的URL
3、返回值:
nameAndUrl、exceptionUrl
"""


def solveExceptionUrl(nameAndUrl, exceptionUrl):
    # 如果异常的URL列表不为空,继续循环
    while len(exceptionUrl) != 0:
        # 遍历异常数组
        for i in exceptionUrl:
            # 如果发生异常,执行下一个URL
            try:
                # 解析URL
                html = parse(i)
                # 如果URL是无效的
                if html.__eq__('<!-- empty -->'):
                    # 移除URL
                    nameAndUrl.remove(i)
                    # 执行下一个URL
                    continue
                else:
                    # 获取该URL的名称
                    name = getName(html)
                    # 名称是全国开头的,才是我们需要的URL
                    if re.match('^全国.*', name):
                        # 把地区名和URL同时加入数组,空格作为分隔符
                        nameAndUrl.append(name + ' ' + i)
                        print('获取' + name + '---成功')
                        # 移除URL
                        exceptionUrl.remove(i)
            except:
                # 执行下一个URL
                continue
    # 返回数组
    return nameAndUrl


"""
1、参数:nameAndUrl是存放地区名称和URL地址的数组
主要功能:把数组中的数据写入文件
返回值:无
"""


def write(nameAndUrl):
    # 把列表中信息写入文件
    with open('nameAndUrl.txt', mode='w', encoding='utf-8') as file:
        for i in nameAndUrl:
            # 写入数据
            file.write(i + '\n')
    print('写入文件成功')


"""
1、参数:html内容
2、主要功能:
根据html获取城市的名称
3、返回值:
城市的名称
"""


def getName(html):
    # 解析HTML
    info = BeautifulSoup(html, "html.parser")
    # 抓取class为crumbs fl的div
    div = info.find(name="div", attrs={"class": "crumbs fl"})
    # 从div中抓取a标签
    a = div.findAll('a')
    # 从div中抓取span标签
    span = div.findAll('span')
    # 城市名
    name = ''
    # 拼接城市名
    for i in a:
        name += i.text + '-'
    name += span[-1].text
    # 返回城市的名称
    return name


if __name__ == '__main__':
    # 存放URL的数组
    nameAndUrl = []
    # 存放发生异常的URL
    exceptionUrl = []
    # 爬取直辖市
    nameAndUrl, exceptionUrl = zhiXiaShi(nameAndUrl, exceptionUrl)
    # 爬取省
    nameAndUrl, exceptionUrl = sheng(nameAndUrl, exceptionUrl)
    # 重新解析异常的URL
    nameAndUrl = solveExceptionUrl(nameAndUrl, exceptionUrl)
    # 把数据写入文件
    write(nameAndUrl)

根据城市URL爬取天气

代码结构图
在这里插入图片描述

import datetime
import requests
from bs4 import BeautifulSoup
from WebWorm.RandomHeader import getRandomHeader

"""
1、参数:
2、主要功能:
读取文件中的URL和Name
返回值:
包含URL和Name的数组
"""


def getURL():
    with open('nameAndUrl.txt', mode='r', encoding='utf-8') as file:
        # 读取文件
        nameAndUrl = file.readlines()
    # 返回数组
    print('读取URL成功')
    return nameAndUrl


"""
1、参数:URL
2、主要功能:
根据URL返回HTML内容
3、返回值:
HTML内容
"""


def parse(url):
    # 设置随机头
    headers = {"user-agent": getRandomHeader()}
    # 请求URL
    request = requests.get(url, headers=headers)
    # 设置编码
    request.encoding = 'utf-8'
    # 请求到的内容
    html = request.text
    # 返回HTML
    return html


"""
1、参数:html页面
2、主要功能:
爬取html页面的天气信息
3、返回值:
包含天气的数组
"""


def getWeatherInfo(html):
    # 存放多组天气的数组
    more = []
    # 解析HTML
    info = BeautifulSoup(html, "html.parser")
    # 抓取class为crumbs fl的div
    li = info.find(name="ul", attrs={"class": "t clearfix"}).find_all('li')
    # 天数
    num = 0
    for i in li:
        # 存放一个城市的天气信息
        one = []
        # 把城市名称加入数组
        one.append(name)
        # 不要当天的数据
        if num == 0:
            num += 1
            continue
        # 今天日期
        today = datetime.datetime.now()
        # 日期+1
        offset = datetime.timedelta(days=+num)
        # 时间并格式化
        date = (today + offset).strftime('%Y-%m-%d')
        # p class="wea" 天气
        wea = i.find(name="p", attrs={"class": "wea"}).text
        # <p class="tem"> 温度  如果是本天 只显示当前温度,所以n号晚上11点爬取,爬取n+1号的天气  <span>10℃</span>/<i>-1℃</i>  <i>-3℃</i>
        maxTem = i.find(name="p", attrs={"class": "tem"}).find('span').text.replace('℃', '')
        minTem = i.find(name="p", attrs={"class": "tem"}).find('i').text.replace('℃', '')
        # <p class="win"> 风
        win = i.find(name="p", attrs={"class": "win"})
        # 风况
        winds = win.find('em').find_all('span')
        wind = ''
        for i in winds:
            wind += i.get('title') + '转'
        # 去除最后一个转
        wind = wind[:-1]
        # 风级
        windNumber = win.find('i').text.replace('&lt;', '小于')
        wind += windNumber
        # 日期+1
        num += 1
        # 把天气数据加入数组
        one.append(date)
        one.append(wea)
        one.append(maxTem)
        one.append(minTem)
        one.append(wind)
        # 把一组数据加入大数组
        more.append(one)
    print('爬取' + name + '成功')
    return more


"""
1、参数:所有的天气信息
2、主要功能:
把爬取到的数据写入文件
3、返回值:
"""


def write(weather):
    with open('weather.txt', mode='w', encoding='utf-8') as file:
        for i in weather:
            # |||作为分隔符
            info = '|||'.join(i)
            # 写入文件
            file.write(info + '\n')
    print('写入文件成功')


if __name__ == '__main__':
    # 存放所有天气的信息的数组
    allWeatherInfo = []
    # 存放异常URL的数组
    exceptionUrl = []
    # 从文件中读取所有的URL
    nameAndUrl = getURL()

    # 遍历URL
    for i in nameAndUrl:
        # 城市名称
        name = i.split(' ')[0]
        # 城市URL
        url = i.split(' ')[1].strip()
        # 如果解析过程中发生了错误异常,把这个URL记录下来,继续下次循环
        try:
            # 获得HTML页面
            html = parse(url)
            # 获得天气信息
            more = getWeatherInfo(html)
            # 把天气信息加入数组
            allWeatherInfo.extend(more)
        except:
            exceptionUrl.append(url)
    # 解决异常URL,知道异常URL数组为空
    while len(exceptionUrl) != 0:
        # 遍历异常URL
        for i in exceptionUrl:
            # 如果URL发生异常,继续循环
            try:
                # 获得HTML页面
                html = parse(i)
                # 得到天气信息
                more = getWeatherInfo(html)
                # 把天气信息加入数组
                allWeatherInfo.extend(more)
                # 爬取成功,移除异常URL
                exceptionUrl.remove(i)
            except:
                continue
    # 把天气信息写入文件
    write(allWeatherInfo)

总结

可以把天气信息插入数据库,也可以每天定时执行脚本,我提供了面粉和水,至于你们想做饺子还是包子,取决于个人。
有问题及时反馈,共同成长。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值