java网页爬虫获取天气信息_爬虫-通过本地IP地址从中国天气网爬取当前城市天气情况...

本文介绍如何利用Python爬虫从中国天气网获取本地城市天气信息。首先通过www.ip.cn获取本地城市名称,然后针对不同情况进行处理,再通过发送HTTP请求获取城市编码,最后使用编码查询天气详情。过程中解决了动态加载页面和403禁止访问的问题。
摘要由CSDN通过智能技术生成

1.问题描述

​最近在做一个pyqt登录校园网的小项目,想在窗口的状态栏加上当天的天气情况,用爬虫可以很好的解决我的问题。

*最新,发现www.ip.cn采用了js动态加载,所以代码有所变化,但整体思路不变

2.解决思路

​考虑到所处位置的不同,需要先获取本地城市地址,然后作为中国天气网的输入,爬取指定城市的天气信息。

​a. 先通过https://www.ip.cn/爬取本地城市名称

282dc8ae58ce978b237dc9050ef6a9b3.png

b. 再通过获取本地城市名称作为输入

2e2d38743c9eed3be9cdd19078c58bba.png

进入城市页面获取所需信息即可,看起来不难,不就是爬、爬吗

e95d2850b5f7f56803338a9bfea79839.png

3.思路实现

​a 很容易实现,直接上代码

def download_page(url):

"""

获取网页源代码

"""

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0'}

html = requests.get(url, headers=headers)

# print(html.text)

return html.text

def get_city_name(html):

"""

对网页内容进行解析并分析得到需要的数据

"""

selector = etree.HTML(html) # 将源码转换为能被XPath匹配的格式

_info = selector.xpath('//script')[1].text # 由于网页采用动态加载,“所在的地理位置”跑到了

location = re.findall(r"(.*?)", _info)[1]

location = location.split(" ")[0]

if location in municipality:

city = location[:-1] # 直辖市的话不取'市',不然天气结果会不准

else:

for i, char in enumerate(location):

if char == "区" or char == "省":

index = i + 1

break

city = location[index:-1] # 取'省'后面一直到'市'中间的城市名称用作天气搜索

return city

我的ip会返回‘合肥’,北京,上海这些直辖市和一些自治区需要特别处理一下才能获得所需城市名,这里必须返回城市名称,不然直接搜索会出现这样,得不到任何天气data,好吧,能给我天气情况就行,要什么自行车:

1502909-20190302225213838-396641465.png

b 的话需要2步走,首先获取城市对于编码

在输入合肥点击搜索之后,通过观察网络请求信息,浏览器发送了一个GET请求,服务器响应数据中包含城市码,如下图

1502909-20190302223753048-1220978595.png

1502909-20190302223758209-1781763570.png

def get_city_code(city='合肥'):

"""

输入一个城市,返回在中国天气网上城市所对应的code

"""

try:

parameter = urlparse.parse.urlencode({'cityname': city})

conn = http.client.HTTPConnection('toy1.weather.com.cn', 80, timeout=5)

conn.request('GET', '/search?'+parameter)

r = conn.getresponse()

data = r.read().decode()[1:-1]

json_data = json.loads(data)

code = json_data[0]['ref'].split('~')[0] # 返回城市编码

return code

except Exception as e:

raise e

模拟发送请求即可,头信息在这,这里&callback和&_参数可以不要,然后对响应做下处理,因为得到的JSON数据字符串,需要将字符串转为JSON数据格式,这就能得到城市码了。

1502909-20190302225602251-1791716801.png

终于到了最后一步,也是最烦,不对,是最难的一步,获取城市天气信息,按说操作思路和上面差不多,就是分析页面数据然后找标签就行了,,,

可是这个网站竟然是javascript动态加载的,获取的页面图上所指的内容啥都没,这要我怎么获取天气情况,对于只会爬取非动态网页的小白,只能留下没技术的眼泪。

1502909-20190302230558804-1507369337.png

​就这样,又去学了一点动态爬取网站的基础知识,通过一个一个请求分析查看,终于找到了我所要的信息,其实只要看响应就行了,服务器js返回的值都在这能看到。

1502909-20190302230723179-947578542.png

接着套路和上面一样,发送一个GET请求等服务器返回数据我们拿来用就行了

。。。。。。。。

1502909-20190302230321308-828433066.png

问题又出现了,这次又是403,还有有人已经走过这条路了,在GET请求加上headers就行了,不让服务器发现这是爬虫,而是认为这是浏览器在请求,结果发现只需要在请求头加上Referer参数就行,看来服务器并没有真正做到反扒。。。。

1502909-20190302230400409-1258259017.png

def get_city_weather(city_code):

"""

通过城市编码找到天气信息

"""

try:

url = 'http://www.weather.com.cn/weather1dn/' + city_code + '.shtml'

# 这里选择的体验新版,所以是1dn,旧版是1d

headers = { "Referer": url }

conn = http.client.HTTPConnection('d1.weather.com.cn', 80, timeout=5)

conn.request('GET', '/sk_2d/' + city_code + '.html', headers=headers)

r = conn.getresponse()

data = r.read().decode()[13:]

weather_info = json.loads(data)

return weather_info

except Exception as e:

raise e

好了,大功告成!

1502909-20190302223833174-1642502021.png

贴一下自己的代码供有需要的人参考:

# -*- coding:utf-8 -*-

# 天气脚本

import json

import re

import urllib as urlparse

import http.client

import requests

from lxml import etree

target_url = 'https://www.ip.cn/'

municipality = ['北京市','上海市','重庆市','天津市']

def download_page(url):

"""

获取网页源代码

"""

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0'}

html = requests.get(url, headers=headers)

# print(html.text)

return html.text

def get_city_name(html):

"""

对网页内容进行解析并分析得到需要的数据

"""

selector = etree.HTML(html) # 将源码转换为能被XPath匹配的格式

_info = selector.xpath('//script')[1].text # 由于网页采用动态加载,“所在的地理位置”跑到了

location = re.findall(r"(.*?)", _info)[1] #使用正则表达式获取地理位置信息,在标签中

location = location.split(" ")[0]

if location in municipality:

city = location[:-1] # 直辖市的话不取'市',不然天气结果会不准

else:

for i, char in enumerate(location):

if char == "区" or char == "省":

index = i + 1

break

city = location[index:-1] # 取'省'后面一直到'市'中间的城市名称用作天气搜索

return city

def get_city_code(city='合肥'):

"""

输入一个城市,返回在中国天气网上城市所对应的code

"""

try:

parameter = urlparse.parse.urlencode({'cityname': city})

conn = http.client.HTTPConnection('toy1.weather.com.cn', 80, timeout=5)

conn.request('GET', '/search?' + parameter)

r = conn.getresponse()

data = r.read().decode()[1:-1]

json_data = json.loads(data)

code = json_data[0]['ref'].split('~')[0] # 返回城市编码

return code

except Exception as e:

raise e

def get_city_weather(city_code):

"""

通过城市编码找到天气信息

"""

try:

url = 'http://www.weather.com.cn/weather1dn/' + city_code + '.shtml'

headers = { "Referer": url }

conn = http.client.HTTPConnection('d1.weather.com.cn', 80, timeout=5)

conn.request('GET', '/sk_2d/' + city_code + '.html', headers=headers)

r = conn.getresponse()

data = r.read().decode()[13:]

weather_info = json.loads(data)

return weather_info

except Exception as e:

raise e

if __name__ == '__main__':

city = get_city_name(download_page(target_url))

city_code = get_city_code(city)

city_wether = get_city_weather(city_code)

print(city_wether)

PS:第一次写博客,markdown刚学还不是很熟,表达可能也有点欠缺。

每次都是从别人那填好的坑走过,这次要填自己的坑,给别人开路

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值