前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Python爬虫实战入门】:全球天气信息爬取

【Python爬虫实战入门】:全球天气信息爬取

作者头像
用户11062259
发布2024-05-08 08:28:11
660
发布2024-05-08 08:28:11
举报
文章被收录于专栏:C语言基础C语言基础

一、爬取需求

目标网站http://www.weather.com.cn/textFC/hb.shtml 需求:爬取全国的天气(获取城市以及最低气温) 目标urlhttp://www.weather.com.cn/textFC/hz.shtml

二、所需第三方库

requests BeautifulSoup4

安装

requestspip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple some-package BeautifulSoup4pip install BeautifulSoup4 -i https://pypi.tuna.tsinghua.edu.cn/simple some-package

2.1 简介

requests模块

官方文档https://requests.readthedocs.io/projects/cn/zh-cn/latest/ requests 是 Python 编程语言中一个常用的第三方库,它可以帮助我们向 HTTP 服务器发送各种类型的请求,并处理响应。

  • 向 Web 服务器发送 GET、POST 等请求方法;
  • 在请求中添加自定义标头(headers)、URL 参数、请求体等;
  • 自动处理 cookies;
  • 返回响应内容,并对其进行解码;
  • 处理重定向和跳转等操作;
  • 检查响应状态码以及请求所消耗的时间等信息。

BeautifulSoup4模块

官方文档https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/ Beautiful Soup 是一个 可以从 HTML 或 XML 文件中提取数据的 Python 库。它能用你喜欢的解析器和习惯的方式实现 文档树的导航、查找、和修改。

下表描述了几种解析器的优缺点:

注意:如果一段文档格式不标准,那么在不同解析器生成的 Beautiful Soup 数可能不一样。 查看 解析器之间的区别 了解更多细节。

数据提取之CSS选择器

  • 熟悉前端的同学对 css 选择器一定不会陌生,比如 jquery 中通过各种 css 选择器语法进行 DOM 操作等
  • 学习网站http://www.w3cmap.com/cssref/css-selectors.html

在爬虫中使用css选择器,代码教程

代码语言:javascript
复制
>>> from requests_html import session

# 返回一个Response对象
>>> r = session.get('https://python.org/')

# 获取所有链接
>>> r.html.links
{'/users/membership/', '/about/gettingstarted/'}

# 使用css选择器的方式获取某个元素
>>> about = r.html.find('#about')[0]

>>> print(about.text)
About
Applications
Quotes
Getting Started
Help
Python Brochure
三、实战案例

目标网站:http://www.weather.com.cn/textFC/hb.shtml

思路分析:

  1. 通过find方法,定位的div class=conMidtab2
  2. 通过find_all方法,找所有的tr标签

函数功能

  1. 得到网页源码
  2. 解析数据
  3. 保存数据
  4. 主函数

程序框架

代码语言:javascript
复制
import requests
from bs4 import BeautifulSoup
# 获取网页源码
def get_html():
    pass
# 解析数据
def parse_html():
    pass
# 保存数据
def save_data():
    pass
# 主函数
def main():
    pass

获取网页源码 在主函数中进行传参调用

代码语言:javascript
复制
# 获取网页源码
def get_html(url):
    html = requests.get(url)
    html.encoding = 'utf-8'
    # print(html.text)
    return html.text

# 主函数
def main():
    url = 'http://www.weather.com.cn/textFC/hz.shtml'
    html = get_html(url)
main()

解析数据get_html函数的返回值(网页源码)作为参数传给parse_html函数

代码语言:javascript
复制
# 主函数
def main():
    url = 'http://www.weather.com.cn/textFC/hz.shtml'
    html = get_html(url)
    parse_html(html)
main()

对于parse_html函数,要将传入的网页源码进行解析,获取我们想要的数据。

通过观察元素,每一个class="conMidtab2"的div标签就代表一个省份,那么他的父级元素class="conMidtab"的div标签就包含三个省份的天气信息,了解了这些,剩下的我们只需要根据元素之间的关系,一步步提取我们想要的数据即可。

代码语言:javascript
复制
# 解析数据
def parse_html(html):
    # 创建对象
    soup = BeautifulSoup(html, 'lxml')
    conMidtab = soup.find('div', class_="conMidtab")
    tables = conMidtab.find_all('table')
    # print(tables)
    for table in tables:
        trs = table.find_all('tr')[2:]
        # print(trs)
        for index, tr in enumerate(trs):
            tds = tr.find_all('td')
            # print(tds)
            city = list(tds[1].stripped_strings)[0]  # 城市
            temp = tds[-2].string  # 最低气温
            print(city, temp)
        break

但是,这里出现了一个问题,那就是我们要打印城市信息的时候,只能打印出第一个城市,后面的城市无法打印出来,通过查看元素后我们会发现,除了第一个城市是在第二个td标签里面,其余城市都在第一个td标签里面,所以在这里我们要将循环改一下,同时还要加一个判断,只要是第一个城市就去第二个td标签,其余的取第一个td标签

想要实现这种效果,我们就要用到一个函数enumerate,这个函数可以将下标和下标对应的值给显示出来。

代码语言:javascript
复制
# 解析数据
def parse_html(html):
    # 创建对象
    soup = BeautifulSoup(html, 'lxml')
    conMidtab = soup.find('div', class_="conMidtab")
    tables = conMidtab.find_all('table')
    # print(tables)
    for table in tables:
        trs = table.find_all('tr')[2:]
        # print(trs)
        for index, tr in enumerate(trs):
            tds = tr.find_all('td')
            # print(tds)
            if index == 0:  # 第一个城市取第二个td标签
                city = list(tds[1].stripped_strings)[0]  # 城市
            else:  # 其余的取第一个td标签
                city = list(tds[0].stripped_strings)[0]  # 城市
            temp = tds[-2].string  # 最低气温
            print(city, temp)

更换url查看数据信息 在主函数里面去更换url,然后查看打印的数据信息是否正确。运行后发现前面的都是正确的,直到更换到港澳台1地区时就出现了问题。

代码语言:javascript
复制
# 主函数
def main():
    # url = 'http://www.weather.com.cn/textFC/hz.shtml'  # 华中地区
    # url = 'http://www.weather.com.cn/textFC/hb.shtml'  # 华北地区
    url = 'http://www.weather.com.cn/textFC/gat.shtml'  # 港澳台地区
    html = get_html(url)
    parse_html(html)
main()

我们发现,我们无法在元素中发现问题,那么我们现在就应该查看一下网页源代码。

查看网页源代码之后可以发现,他所在的table标签是没有结束标签的,后面的城市的table标签也没有结束标签,这也就导致了数据混乱。 想要解决这个问题,就需要更换一下解析器。上面在提到BeautifulSoup4时的解析器,我们发现html5lib这个解析器拥有最好的容错性。

下载pip install html5lib

代码语言:javascript
复制
# 解析数据
def parse_html(html):
    # 创建对象
    soup = BeautifulSoup(html, 'html5lib')  # 将lxml换成html5lib
    conMidtab = soup.find('div', class_="conMidtab")
    tables = conMidtab.find_all('table')
    # print(tables)
    for table in tables:
        trs = table.find_all('tr')[2:]
        # print(trs)
        for index, tr in enumerate(trs):
            tds = tr.find_all('td')
            # print(tds)
            if index == 0:  # 第一个城市取第二个td标签
                city = list(tds[1].stripped_strings)[0]  # 城市
            else:  # 其余的取第一个td标签
                city = list(tds[0].stripped_strings)[0]  # 城市
            temp = tds[-2].string  # 最低气温
            print(city, temp)

页面切换 要实现页面切换首先我们要观察一下不同页面的url

华北:http://www.weather.com.cn/textFC/hb.shtml 东北:http://www.weather.com.cn/textFC/db.shtml 华南:http://www.weather.com.cn/textFC/hn.shtml 华中:http://www.weather.com.cn/textFC/hz.shtml 港澳台:http://www.weather.com.cn/textFC/gat.shtml

我们发现,这些url的不同之处就在于后面的字母的不同,而这些字母又恰好是地区的首字母,那么我们只需要将这些地区的首字母存入到一个列表当中,循环之后就可以实现页面的切换。

代码语言:javascript
复制
# 主函数
def main():
    district = ['hb', 'db', 'hd', 'hz', 'hn', 'xb', 'xn', 'gat']
    # url = 'http://www.weather.com.cn/textFC/hz.shtml'
    # url = 'http://www.weather.com.cn/textFC/hb.shtml'
    for dist in district:
        url = f'http://www.weather.com.cn/textFC/{dist}.shtml'
        html = get_html(url)
        parse_html(html)
main()

数据保存 定义一个全局变量的列表list_data,在解析数据的第二层循环中定义一个字典,将城市和最低气温添加到字典中去,最后将字典添加到list_data列表中。

代码语言:javascript
复制
# 保存数据
def save_data():
    with open('全国天气.csv', 'w', encoding='utf-8-sig', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=('城市', '最低气温'))
        writer.writeheader()
        writer.writerows(list_data)
四、完整代码
代码语言:javascript
复制
import requests
from bs4 import BeautifulSoup
import csv


list_data = []
# 获取网页源码
def get_html(url):
    html = requests.get(url)
    html.encoding = 'utf-8'
    # print(html.text)
    return html.text


# 解析数据
def parse_html(html):
    # 创建对象
    soup = BeautifulSoup(html, 'html5lib')  # 将lxml换成html5lib
    conMidtab = soup.find('div', class_="conMidtab")
    tables = conMidtab.find_all('table')
    # print(tables)
    for table in tables:
        trs = table.find_all('tr')[2:]
        # print(trs)
        for index, tr in enumerate(trs):
            dic = {}
            tds = tr.find_all('td')
            # print(tds)
            if index == 0:  # 第一个城市取第二个td标签
                city = list(tds[1].stripped_strings)[0]  # 城市
            else:  # 其余的取第一个td标签
                city = list(tds[0].stripped_strings)[0]  # 城市
            dic['城市'] = city
            temp = tds[-2].string  # 最低气温
            dic['最低气温'] = temp
            list_data.append(dic)


# 保存数据
def save_data():
    with open('全国天气.csv', 'w', encoding='utf-8-sig', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=('城市', '最低气温'))
        writer.writeheader()
        writer.writerows(list_data)


# 主函数
def main():
    district = ['hb', 'db', 'hd', 'hz', 'hn', 'xb', 'xn', 'gat']
    # url = 'http://www.weather.com.cn/textFC/hz.shtml'
    # url = 'http://www.weather.com.cn/textFC/hb.shtml'
    for dist in district:
        url = f'http://www.weather.com.cn/textFC/{dist}.shtml'
        html = get_html(url)
        parse_html(html)
    save_data()  # 数据保存

main()
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-05-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二、所需第三方库
    • 2.1 简介
    • 三、实战案例
    • 四、完整代码
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档