抓取中国天气网当前时段所有城市的天气数据(python+xpath)

爬虫 专栏收录该内容
9 篇文章 0 订阅

先给大家看一看效果图(我一共获取到了462个城市的天气):
效果图
前不久,2019年开放数据中心峰会在北京国际会议中心成功召开,ODCC指出:“对数据进行汇聚,在体系化融合中产生新的价值已成为未来发展的关键”

在DT时代,谁拥有数据,谁就有筹码。话不多说,我们先来了解一下,什么是大数据?简单来说,假如你是一名气象员,负责统计某个城市的天气情况(最高温度、最低温度、风速等等),如果你每小时统计一次,那么,一天下来,你可以获得24条数据,如果你雇了很多人一起统计你所在城市的每个城区的天气,假设该城市有5个城区,那么,你在一天之内就能收集245=120条数据,再把范围扩大,我们把全国各个城市的天气数据汇聚在一起,(我查了一下,截止2018年,全国共有661个市),那么你在一天之内,就收集到了120661=79320条数据!这仅仅只是一天的数据,如果你坚持一周、一个月甚至更久…

那么,我们现在就开始收集数据吧!(我虽然不是气象员,但是我可以通过程序获取天气数据,数据来源:中国天气网)中国天气网没有运用ajax等加载技术,这样比较方便一个爬虫新手对其进行爬取,在爬取过程中只需要对一些文本进行格式化就行,网上有很多爬中国天气网的教程,这里就不详细说了,我只说一下我改进的地方:

  • 每次运行程序时可以自动创建数据表,把抓取下来的数据存进MySQL数据库中,按照时间建立数据表,方便日后做数据分析
  • 网上的教程没有讲港澳台地区的数据要怎么爬(说是因为表格结构不同),我为了数据的完整性,把抓取港澳台地区数据的问题解决了
  • 对比BeautifulSoup 和 Xpath 这两种方法.在爬港澳台地区数据时,我用了xpath

在这里,我将用到面向对象编程.首先使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾:

class Inquire(object):

init()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法:

def __init__(self):

self 代表类的实例,self 在定义类的方法时是必须有的,在调用时不必传入相应的参数

接下来,我们来连接一下数据库:

self.conn = connect(host = '127.0.0.1',
                    port = 3306,
                    user = 'root',
                    password = 'root',
                    charset = 'utf8',
                    db = 'asset')
self.cursor = self.conn.cursor()
print("数据库连接成功!")

输出一个结果用来表示连接成功,这里是程序的最开始部分,更优的写法应该是这样的:

try:
	self.conn = connect(host = '127.0.0.1',
                        port = 3306,
                        user = 'root',
                        password = 'root',
                        charset = 'utf8',
                        db = 'asset')
    self.cursor = self.conn.cursor()
    print("数据库连接成功!")
except Exception as e:
    print(e)

接下来,我来讲一下我的想法:

获取当前的时间,以当前时间给数据表命名,为了防止一天要运行多次程序,我在后面添上了”a+数字”,20190928a1则表示2019年9月28日的第一张table, 20190928a2则表示2019年9月28日的第二张table,以此类推… …

def ticks_time(self):
        ticks = time.strftime("%Y%m%da1", time.localtime())
        print("当前时间为:", ticks)
        return ticks

有了给数据表建表的名称,我们开始创建数据表:

def creat_table(self):
        ticks = self.ticks_time()
        self.cursor.execute("CREATE TABLE `%s` (id INT AUTO_INCREMENT PRIMARY KEY,city  CHAR(10),weather CHAR(10),wind CHAR(20),max CHAR(10),min CHAR(10))"%ticks)
        print("数据表创建成功!")

我们来看一下数据表创建成功后,在MySQL里显示的结果:
数据表结构
接下来就到数据抓取的部分了,我主要讲如何爬港澳台地区的数据,先来看一下港澳台地区的网页结构:
网页结构
根据这个结构,我们可以分析:

  1. 首先要定位到hanml, 因为下面有很多个comMidtab
    在这里插入图片描述
  2. 通过hanml定位到comMidtab
  3. 取出第一个conMidtab
  4. 定位到下面的table标签
    定位table标签
  5. 循环该节点下的table
  6. 通过每个table定位到第三个tr
  7. 从第三个tr开始,取出tr下的所有td,并且找到相应的文字内容

还是挺复杂的,但是没关系,分步骤来进行,就会变得很简单,开始写代码!

url = "http://www.weather.com.cn/textFC/gat.shtml"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"}
html = requests.get(url=url,headers=headers)
selector = etree.HTML(html.content,parser=etree.HTMLParser(encoding='utf8'))

前几句都是常规操作了,我讲讲最后一句,我一开始就是在这里遇到了不少问题.

我直接使用lxml的etree.HTML处理源代码,然后Xpath提取内容时,出现了乱码,我上网查了一下,找到了原因:处理源文件的时候,由于没有指定编码,所以它使用了一个默认编码,从而导致和UTF-8冲突,产生乱码。经过查阅lxml.etree.HTML的文档,我发现etree.HTML有一个参数是parser,这个参数不是必须的,因此省略以后它就会自动使用一个默认的parser。

既然如此,那我手动指定一个:

etree.HTML(html.content, parser=etree.HTMLParser(encoding='utf8'))

这里我指定了etree.HTMLParser来作为一个parser,同时,etree.HTMLParser可以接受编码作为参数。于是我指定为UTF-8.

到这一步以后,我们开始定位元素.

定位hanml:

hanml = selector.xpath("//div[@class='hanml']")[0]

定位hanml下的conMidtab:

conMidtab = hanml.xpath("./div[@class='conMidtab']")[0]

定位conMidtab下的table标签:

tables = conMidtab.xpath("./div[@class='conMidtab2']//table")[0:3]

循环该节点下的table, 过每个table定位到第三个tr:

for table in tables:
    	tr_list = table.xpath("./tr")[2:]

从第三个tr开始,取出tr下的所有td,并且找到相应的文字内容:

for index,tr_list in enumerate(tr_list):
    	td_list = tr_list.xpath("./td//text()")

我们来打印一下:
打印td_list
我拿出来给大家看:

[’\n’, ‘香港’, ‘\n’, ‘\n’, ‘香港’, ‘晴’, ‘\n’, ‘无持续风向’, ‘\n’, ‘<3级’, ‘32’, ‘晴’, ‘\n’, ‘无持续风向’, ‘\n’, ‘<3级’, ‘26’, ‘\n’, ‘详情’]
[’\n’, ‘澳门’, ‘\n’, ‘\n’, ‘澳门’, ‘多云’, ‘\n’, ‘无持续风向’, ‘\n’, ‘<3级’, ‘32’, ‘多云’, ‘\n’, ‘无持续风向’, ‘\n’, ‘<3级’, ‘25’, ‘\n’, ‘详情’]
[’\n’, ‘台湾’, ‘\n’, ‘\n’, ‘台北’, ‘小雨’, ‘\n’, ‘东北风’, ‘\n’, ‘3-4级’, ‘26’, ‘小雨’, ‘\n’, ‘东风’, ‘\n’, ‘3-4级’, ‘23’, ‘\n’, ‘详情’]
[’\n’, ‘高雄’, ‘晴’, ‘\n’, ‘无持续风向’, ‘\n’, ‘<3级’, ‘28’, ‘晴’, ‘\n’, ‘无持续风向’, ‘\n’, ‘<3级’, ‘25’, ‘\n’, ‘详情’]
[’\n’, ‘台中’, ‘小雨’, ‘\n’, ‘无持续风向’, ‘\n’, ‘<3级’, ‘26’, ‘晴’, ‘\n’, ‘无持续风向’, ‘\n’, ‘<3级’, ‘21’, ‘\n’, ‘详情’]

可以看到,前三行和后两行的长度是不一样的,我第一次就踩了这个坑,因此,我们要做一个判断.在这里,我用列表长度做的判断:

len_td = len(td_list)
if len_td == 19:
    city_name = td_list[4]
    weather = td_list[11]
    wind = td_list[13]
    max = td_list[10]
    min = td_list[16]
else:
    city_name = td_list[1]
    weather = td_list[8]
    wind = td_list[10]
    max = td_list[13]
    min = td_list[7]

否则在匹配时会出现错位的情况,再打印一下:

print(city_name, weather, wind, max, min)

结果是:

香港 晴 无持续风向 32 26
澳门 多云 无持续风向 32 25
台北 小雨 东风 26 23
高雄 晴 无持续风向 25 28
台中 晴 无持续风向 21 26

完美!我们开始导入数据库:

sql = 'insert into %s(city,weather,wind,max,min)'%ticks + 'value(%s,%s,%s,%s,%s)'
self.cursor.execute(sql,[city_name,weather,wind,max,min])
self.conn.commit()

到这里就结束了!我们来看看数据库表的表数据:
在这里插入图片描述
我省略了部分代码,在这里我只展示代码的缩略图.,如有需要,可以联系我:

QQ:2733821739 哓哓晓培

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

  • 0
    点赞
  • 0
    评论
  • 9
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 博客之星2020 设计师:CY__ 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值