Python | 一个简单爬虫爬取天气预报(教程)

Python | 一个简单爬虫爬取天气预报(教程),第1张

一、什么是爬虫 1.定义

爬虫 —— 请求网站并提取数据的自动化程序

2.爬虫的基本流程

(1) 向服务器发起请求
(2) 获取响应内容
(3) 解析内容
(4) 保存数据

二、流程

准备爬取的网址:中国气象局-天气预报 (cma.cn)https://weather.cma.cn/

1、如何爬取不同城市的天气预报

查看 中国气象局-天气预报 页面的源代码。在源代码中,有:

可以发现:每个城市对应天气预报的URL都有如下形式:

weather.cma.cn/web/weather/XXXXX.html

为分别爬取不同城市的天气预报,可以创建列表,分别保存每个城市的名称以及对应的编码,通过遍历列表list的方式访问每个城市的URL,进而进行对其页面的爬取。

weather.cma.cn/web/weather/ + list[i]

爬取的代码如下:

citynum_list = [58367, 51463, 52889, 54511, 58238, 58606, 58968, 58321, 53463, 50953, 53772, 59287, 56294, 55591, 56778,
                58457, 57494, 54342, 54823, 59758, 59493, 53698, 58847, 52866, 57036, 57816, 57083, 57516, 53614, 54161,
                57679, 54517, 45005, 45011, 59431]
cityname_list = ['上海', '乌鲁木齐', '兰州', '北京', '南京', '南昌', '台北', '合肥', '呼和浩特', '哈尔滨', '太原', '广州', '成都', '拉萨', '昆明', '杭州',
                 '武汉', '沈阳', '济南', '海口', '深圳', '石家庄', '福州', '西宁', '西安', '贵阳', '郑州', '重庆', '银川', '长春', '长沙', '天津', '香港',
                 '澳门', '南宁']

def AskURL(url):
    head = {
        "User-Agent": "Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 80.0.3987.122  Safari / 537.36"}
    request = urllib.request.Request(url, headers=head)
    html = ""
    try:
        response = urllib.request.urlopen(request)
        html = response.read().decode("utf-8")
    except urllib.error.URLError as e:
        if hasattr(e, "code"):
            print(e.code)
        if hasattr(e, "reason"):
            print(e.reason)
    return html

# 爬取资源
def GetData(baseurl, citynum_list, cityname_list):
    citydate_list = []
    # 1.获取页面
    for i in range(len(citynum_list) - 1):
        url = baseurl + str(citynum_list[i])
        html = AskURL(url)
        pass
..........................

2、如何从爬取的页面中筛选有用的信息

(1)BeautifulSoup库
查看页面源代码,可以发现,我们需要的信息在块 以及 中,可以采用BeautifulSoup的.find_all方法找到对应的块

soup = BeautifulSoup(html, "html.parser")
# I.当天
for firstdata in soup.find_all('div', class_="pull-left day actived"):
    pass
# II.后面的日子
 for afterdata in soup.find_all('div', class_="pull-left day"):
    pass

 firstdata的结果:

​ afterdata的结果:

​ 这样就获得了一个城市一星期的天气预报,然后就可以使用正则表达式对关心的信息进行筛选了。

(2)Re库

正则表达式预处理

find_day = re.compile(r'(.*?)
(.*?)') find_weather = re.compile(r'(.*?)') find_temperature = re.compile(r'(.*?)(.*?)')

find_day 的代码:

day = re.findall(find_day, firstdata)[0]
            data.append(day[0])
            data.append(day[1])

find_weather  的代码:

 for i in range(1, 7):
                weather = re.findall(find_weather, firstdata)[i]
                data.append(weather)

find_temperature 的代码:

temperature = re.findall(find_temperature, firstdata)[0]
            data.append(temperature[0])
            data.append(temperature[1])

3、保存为Excel文件 (1).xlwt库、xlrd库

保存为excel表的代码:

def SaveExcel(citydate_list, savepath):
    book = xlwt.Workbook(encoding="utf-8", style_compression=0)
    sheet = book.add_sheet('最近7天天气预报', cell_overwrite_ok=True)
    # 标题
    col = ("城市", "星期", "日期", "白天天气", "白天风向", "白天风级", "夜间天气", "夜间风向", "夜间风级", "最高气温", "最低气温")
    for i in range(0, 11):
        sheet.write(0, i, col[i])
    # 城市
    flag = 1
    for i in range(0, len(citydate_list) - 1):
        for weekdata in range(0, 7):
            sheet.write(flag, 0, citydate_list[i][0])
            flag = flag + 1
    # 星期
    for col in range(0, 10):
        flag = 1
        for i in range(0, len(citydate_list) - 1):
            for weekdata in range(1, 8):
                sheet.write(flag, col + 1, citydate_list[i][weekdata][col])
                flag = flag + 1
    book.save(savepath)
    print("文件保存成功!")
    print('\n\n\n',citydate_list)

三、源代码
  • 源代码:
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
from psycopg2 import connect
import urllib.request
import xlwt
import xlrd
import re
import os

# 正则表达式预编译
find_day            = re.compile(r'(.*?)
(.*?)') find_weather = re.compile(r'(.*?)') find_temperature = re.compile(r'(.*?)(.*?)') # 待爬取的城市代码 citynum_list = [58367, 51463, 52889, 54511, 58238, 58606, 58968, 58321, 53463, 50953, 53772, 59287, 56294, 55591, 56778, 58457, 57494, 54342, 54823, 59758, 59493, 53698, 58847, 52866, 57036, 57816, 57083, 57516, 53614, 54161, 57679, 54517, 45005, 45011, 59431] cityname_list = ['上海', '乌鲁木齐', '兰州', '北京', '南京', '南昌', '台北', '合肥', '呼和浩特', '哈尔滨', '太原', '广州', '成都', '拉萨', '昆明', '杭州', '武汉', '沈阳', '济南', '海口', '深圳', '石家庄', '福州', '西宁', '西安', '贵阳', '郑州', '重庆', '银川', '长春', '长沙', '天津', '香港', '澳门', '南宁'] def AskURL(URL): ''' 爬取指定URL的HTML页面 :param URL: 统一资源定位符(UniformResourceLocator) :return: 爬取的HTML页面 ''' # User - Agent 用户代理 head = {"User-Agent": "Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 80.0.3987.122 Safari / 537.36"} # Request类来构建一个请求,在请求中需要加入headers(请求头)等信息 request = urllib.request.Request(URL, headers = head) HTML = "" try: response = urllib.request.urlopen(request) HTML = response.read().decode("utf-8") except urllib.error.URLError: print('网页爬取失败!') return HTML def GetData(Basis_URL, citynum_list, cityname_list): ''' 爬取页面,对页面进行解析 :param Basis_URL: 待爬取页面的基础URL :param citynum_list: 每个城市对应的URL后缀列表 :param cityname_list: 每个城市的城市名列表 :return: citydate_list 包含需要的信息 ''' ''' allcity_list[] ---> 保存包含35个城市的城市名,每个城市7天天气 city_list[] ---> 保存每个城市7天天气 data[] ---> 保存一个城市每天的天气预报情况 ''' allcity_list = [] # 1.获取页面 for i in range(len(citynum_list) - 1): URL = Basis_URL + str(citynum_list[i]) html = AskURL(URL) city_list = [cityname_list[i]] # 2.解析页面 soup = BeautifulSoup(html, "html.parser") # I.当天 for firstdata in soup.find_all('div', class_="pull-left day actived"): data = [] firstdata = str(firstdata) # i.日期 day = re.findall(find_day, firstdata)[0] data.append(day[0]) data.append(day[1]) # ii.天气 for i in range(1, 7): weather = re.findall(find_weather, firstdata)[i] data.append(weather) # iii.温度 temperature = re.findall(find_temperature, firstdata)[0] data.append(temperature[0]) data.append(temperature[1]) city_list.append(data) # II.后面的日子 for afterdata in soup.find_all('div', class_="pull-left day"): data = [] afterdata = str(afterdata) # i.日期 day = re.findall(find_day, afterdata)[0] data.append(day[0]) data.append(day[1]) # ii.天气 for i in range(1, 7): weather = re.findall(find_weather, afterdata)[i] data.append(weather) # iii.温度 temperature = re.findall(find_temperature, afterdata)[0] data.append(temperature[0]) data.append(temperature[1]) city_list.append(data) # 3.展示爬取结果 for i in range(8): print(city_list[i]) print('\n') # 4.加入到总列表中 allcity_list.append(city_list) return allcity_list def SaveExcel(allcity_list, Path): ''' 保存为本地Excel文件 :param allcity_list: 保存包含35个城市的城市名,每个城市7天天气 :param Path: 保存路径 :return: Excel文件 ''' book = xlwt.Workbook(encoding="utf-8", style_compression=0) sheet = book.add_sheet('最近7天天气预报', cell_overwrite_ok=True) # 标题 col = ("城市", "星期", "日期", "白天天气", "白天风向", "白天风级", "夜间天气", "夜间风向", "夜间风级", "最高气温", "最低气温") for i in range(0, 11): sheet.write(0, i, col[i]) # 城市 flag = 1 for i in range(0, len(allcity_list) - 1): for weekdata in range(0, 7): sheet.write(flag, 0, allcity_list[i][0]) flag = flag + 1 # 星期 for col in range(0, 10): flag = 1 for i in range(0, len(allcity_list) - 1): for weekdata in range(1, 8): sheet.write(flag, col + 1, allcity_list[i][weekdata][col]) flag = flag + 1 book.save(Path) print("文件保存成功!") def SaveDataBase(allcity_list,Path): ''' 保存到数据库系统中 :param allcity_list: 保存包含35个城市的城市名,每个城市7天天气 :param Path: Excel文件保存的路径 :return: ''' CreateTable(CreateConnect()) InsertTable(CreateConnect(), allcity_list,Path) # DropTable(CreateConnect()) def CreateConnect(): ''' 连接数据库 :return: ''' try: # 获取环境变量 # 环境变量是程序和 *** 作系统之间的通信方式 # 有些字符不宜明文写进代码里,比如个人账户密码,如果写进自己本机的环境变量里,程序用的时候通过 os.environ.get() 取出来就行了 env = os.environ # 如果成功打开数据库时,返回一个连接对象 params = { 'database': env.get('OG_DATABASE', 'postgres'), # 数据库名称 'user': env.get('OG_USER', 'tom'), # 用户名 'password': env.get('OG_PASSWORD', 'Huawei_123'), # 密码 'host': env.get('OG_HOST', '192.168.56.130'), # 主机IP 'port': env.get('OG_PORT', 26000) # 端口号 } conn: connection = connect(**params) return conn except: print('数据库连接失败!') def CreateTable(conn): ''' 创建表 :param conn: 连接对象 :return: ''' # 创建一个光标将用于整个数据库使用Python编程 cursor = conn.cursor() # 执行SQL语句 cursor.execute('''drop table if exists WeatherForecast''') cursor.execute('''create table WeatherForecast( id integer not null primary key, city_name varchar(500) not null, weekdate varchar(32), date varchar(32), day_weather varchar(50), day_wind_direct varchar(50), day_wind_scale varchar(50), night_weather varchar(50), night_wind_direct varchar(50), night_wind_scale varchar(50), highest_temperature varchar(32), lowest_temperature varchar(32) )''') # 提交当前事务 conn.commit() # 此方法关闭数据库连接,这并不自动调用commit()。如果只是关闭数据库连接而不调用commit()方法,所有更改将会丢失 conn.close() print('数据库创建成功!') def InsertTable(conn, citydate_list,Path): ''' 插入数据 :param conn: 连接对象 :param citydate_list: 保存包含35个城市的城市名,每个城市7天天气 :param Path: Excel文件保存的路径 :return: ''' cursor = conn.cursor() # 读取Excel文件 workBook = xlrd.open_workbook(Path) # 按索引号获取Content内容,sheet索引从0开始 Content = workBook.sheet_by_index(0) # 写入数据库 for i in range(1, Content.nrows): row = Content.row_values(i) cursor.execute(f"insert into WeatherForecast(id,city_name,weekdate,date,day_weather,day_wind_direct,day_wind_scale,night_weather,night_wind_direct,night_wind_scale,highest_temperature,lowest_temperature) values({i},'{row[0]}','{row[1]}','{row[2]}','{row[3]}','{row[4]}','{row[5]}','{row[6]}','{row[7]}','{row[8]}','{row[9]}','{row[10]}')") conn.commit() conn.close() print('数据库插入完毕!') def DropTable(conn): ''' 删除表 :param conn: 连接对象 :return: ''' cursor = conn.cursor() cursor.execute("drop table WeatherForecast") conn.commit() conn.close() print('数据库删除成功!') if __name__ == "__main__": Basis_URL = "https://weather.cma.cn/web/weather/" Path = "各省会城市最近7天天气预报.xls" # 1.爬取网页 allcity_list = GetData(Basis_URL, citynum_list, cityname_list) # 2.保存到Excel文件中 SaveExcel(allcity_list, Path) # 3.保存到数据库中 # SaveDataBase(allcity_list, Path) print("天气爬取完毕!")
  • 运行结果:

  • 保存结果:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/786113.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-04
下一篇 2022-05-04

发表评论

登录后才能评论

评论列表(0条)

保存