设为首页收藏本站

Crossin的编程教室

 找回密码
 立即加入
查看: 154840|回复: 199
打印 上一主题 下一主题

【Python 第46课】 查天气(4)

  [复制链接]

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

跳转到指定楼层
#
发表于 2013-7-27 00:01:01 |只看该作者 |正序浏览
python 查天气系列:
【Python 第43课】 查天气(1) http://bbs.crossincode.com/forum.php?mod=viewthread&tid=8
【Python 第44课】 查天气(2) http://bbs.crossincode.com/forum.php?mod=viewthread&tid=9
【Python 第45课】 查天气(3) http://bbs.crossincode.com/forum.php?mod=viewthread&tid=12
【Python 第46课】 查天气(4) http://bbs.crossincode.com/forum.php?mod=viewthread&tid=42


这一课算是“查天气”程序的附加内容。没有这一课,你也查到天气了。但了解一下城市代码的抓取过程,会对网页抓取有更深的理解。

天气网的城市代码信息结构比较复杂,所有代码按层级放在了很多xml为后缀的文件中。而这些所谓的“xml”文件又不符合xml的格式规范,导致在浏览器中无法显示,给我们的抓取又多加了一点难度。

首先,抓取省份的列表:
  1. url1 = 'http://m.weather.com.cn/data3/city.xml'
  2. content1 = urllib2.urlopen(url1).read()
  3. provinces = content1.split(',')
复制代码
输出content1可以查看全部省份代码:
  1. 01|北京,02|上海,03|天津,...
复制代码
对于每个省,抓取城市列表:
  1. url = 'http://m.weather.com.cn/data3/city%s.xml'
  2. for p in provinces:
  3.     p_code = p.split('|')[0]
  4.     url2 = url % p_code
  5.     content2 = urllib2.urlopen(url2).read()
  6.     cities = content2.split(',')
复制代码
输出content2可以查看此省份下所有城市代码:
  1. 1901|南京,1902|无锡,1903|镇江,...
复制代码
再对于每个城市,抓取地区列表:
  1. for c in cities[:3]:
  2.     c_code = c.split('|')[0]
  3.     url3 = url % c_code
  4.     content3 = urllib2.urlopen(url3).read()
  5.     districts = content3.split(',')
复制代码
content3是此城市下所有地区代码:
  1. 190101|南京,190102|溧水,190103|高淳,...
复制代码
最后,对于每个地区,我们把它的名字记录下来,然后再发送一次请求,得到它的最终代码:
  1. for d in districts:
  2.     d_pair = d.split('|')
  3.     d_code = d_pair[0]
  4.     name = d_pair[1]
  5.     url4 = url % d_code
  6.     content4 = urllib2.urlopen(url4).read()
  7.     code = content4.split('|')[1]
复制代码
name和code就是我们最终要得到的城市代码信息。它们格式化到字符串中,最终保存在文件里:
  1. line = "    '%s': '%s',\n" % (name, code)
  2. result += line
复制代码
同时你也可以输出它们,以便在抓取的过程中查看进度:
  1. print  name + ':' + code
复制代码
完整代码:
  1. import urllib2

  2. url1 = 'http://m.weather.com.cn/data3/city.xml'
  3. content1 = urllib2.urlopen(url1).read()
  4. provinces = content1.split(',')
  5. result = 'city = {\n'
  6. url = 'http://m.weather.com.cn/data3/city%s.xml'
  7. for p in provinces:
  8.     p_code = p.split('|')[0]
  9.     url2 = url % p_code
  10.     content2 = urllib2.urlopen(url2).read()
  11.     cities = content2.split(',')
  12.     for c in cities:
  13.         c_code = c.split('|')[0]
  14.         url3 = url % c_code
  15.         content3 = urllib2.urlopen(url3).read()
  16.         districts = content3.split(',')
  17.         for d in districts:
  18.             d_pair = d.split('|')
  19.             d_code = d_pair[0]
  20.             name = d_pair[1]
  21.             url4 = url % d_code
  22.             content4 = urllib2.urlopen(url4).read()
  23.             code = content4.split('|')[1]
  24.             line = "    '%s': '%s',\n" % (name, code)
  25.             result += line
  26.             print  name + ':' + code
  27. result += '}'
  28. f = file('/home/crossin/Desktop/city.py', 'w')
  29. f.write(result)
  30. f.close()
复制代码
如果你只是想抓几个测试一下,并不用全部抓下来,在provices后面加上[:3],抓3个省的试试看就好了。

补充:如果发现输出的是乱码(这种事往往发生在windows下),试着把输出那行改为
  1. print  name.decode('utf-8') + ':' + code
复制代码


#==== Crossin的编程教室 ====#
微信ID:crossincode
QQ群:312723402

面向零基础初学者的编程课
每天5分钟,轻松学编程


#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

199#
发表于 2019-11-27 23:17:48 |只看该作者
PMCoding 发表于 2019-11-27 14:17
import urllib.request

url1 = 'http://m.weather.com.cn/data3/city.xml'

是的,这个方式的接口已经失效,可以公众号回复 查天气,里面有新的方法
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

0

主题

1

好友

34

积分

新手上路

Rank: 1

198#
发表于 2019-11-27 14:17:21 |只看该作者
import urllib.request

url1 = 'http://m.weather.com.cn/data3/city.xml'

content1 = urllib.request.urlopen(url1).read()
content1 = content1.decode('utf8')
provinces = content1.split(',')
print(content1)
print(provinces)

结果:

<html style="font-size: 100px;">

<head>
    <meta charset="utf-8">
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" name="viewport">
    <link rel="apple-touch-icon-precomposed" href="https://i.tq121.com.cn/i/wap/icon.jpg">
    <title>中国天气网-专业天气预报、气象服务门户</title>
    <script type="text/javascript" src="https://i.tq121.com.cn/j/wap2017/base-loading.js?45"></script>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        body {
            background: #ccf2ff;


取到的原始数据已经变了?还是我取得方式不对,怎么没取到省了= =,PY3,谢谢热心大神解答
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

197#
发表于 2019-1-18 21:24:54 |只看该作者
waterzoo 发表于 2019-1-18 18:15
求大神给一个能够在python3下能够运行的代码。我修改了其中一部分,但是还是报错。代码如下:
import urlli ...

py3取到的 content 要转一下

content = content.decode('utf8')
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

1

主题

1

好友

39

积分

新手上路

Rank: 1

196#
发表于 2019-1-18 18:15:41 |只看该作者
求大神给一个能够在python3下能够运行的代码。我修改了其中一部分,但是还是报错。代码如下:
import urllib.request
url1 = 'http://m.weather.com.cn/data3/city.xml'
content1 = urllib.request.urlopen(url1).read()
provinces = content1.split(',')
result = 'city = {\n'
url = 'http://m.weather.com.cn/data3/city%s.xml'
for p in provinces:
    p_code = p.split('|')[0]
    url2 = url % p_code
    content2 = urllib2.urlopen(url2).read()
    cities = content2.split(',')
    for c in cities:
        c_code = c.split('|')[0]
        url3 = url % c_code
        content3 = urllib2.urlopen(url3).read()
        districts = content3.split(',')
        for d in districts:
            d_pair = d.split('|')
            d_code = d_pair[0]
            name = d_pair[1]
            url4 = url % d_code
            content4 = urllib2.urlopen(url4).read()
            code = content4.split('|')[1]
            line = "    '%s': '%s',\n" % (name, code)
            result += line
            print(name + ':' + code)
result += '}'
f = file('/home/crossin/Desktop/city.py', 'w')
f.write(result)
f.close()
报错文字:
  File "D:/python/城市抓取.py", line 4, in <module>
    provinces = content1.split(',')
TypeError: a bytes-like object is required, not 'str'
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

195#
发表于 2019-1-6 17:10:16 |只看该作者
yby15 发表于 2019-1-5 13:43
line="   '%s': '%s',\n"%(name,code) 老师为什么这里双引号和单引号要一起使用,不能只用外面的双引号吗, ...

里面的单引号就是需要单引号这个符号
因为你是要生成一段代码,这代码里需要单引号


json在传输数据时使用,要看双方的约定
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

0

主题

0

好友

24

积分

新手上路

Rank: 1

194#
发表于 2019-1-5 13:43:02 |只看该作者
line="   '%s': '%s',\n"%(name,code) 老师为什么这里双引号和单引号要一起使用,不能只用外面的双引号吗,还有json在什么情况下会用到呢
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

193#
发表于 2018-10-26 00:48:21 |只看该作者
yiminzheng 发表于 2018-10-25 17:16
打印出结果之后,发现原本city.py被修改了

网络read() 出来的结果要decode('utf8'),或者建议用 requests 模块

另外你没拿到code,肯定是最后的请求有问题,多加print看看是哪里不对

公众号回复 查天气,有篇关于这些错误的讨论文章
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

192#
发表于 2018-10-26 00:45:19 |只看该作者
zorro 发表于 2018-10-23 21:14
provinces=content1.split(',')
在这一步报错,TypeError: a bytes-like object is required, not 'str'
不 ...

前面加一行 content1 = content1.decode('utf8')
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

0

主题

0

好友

22

积分

新手上路

Rank: 1

191#
发表于 2018-10-25 17:16:12 |只看该作者
打印出结果之后,发现原本city.py被修改了

TIM截图20181025171509.png (46.17 KB, 下载次数: 823)

TIM截图20181025171509.png

回复

使用道具 举报

0

主题

0

好友

22

积分

新手上路

Rank: 1

190#
发表于 2018-10-25 17:12:52 |只看该作者
hi 先生 麻烦解答一下 自己倒腾修改了一点 Python 3.6.3 win
# -*- coding: cp936 -*-
import urllib.request

url1 = 'http://m.weather.com.cn/data3/city.xml'
content1 = urllib.request.urlopen(url1).read()
provinces = content1.split(','.encode())
result = 'city = {\n'
url = 'http://m.weather.com.cn/data3/city%s.xml'

for p in provinces[:3]:
    p_code = p.split('|'.encode())[0].decode()
    url2 = url % p_code
    content2 = urllib.request.urlopen(url2).read()
    cities = content2.split(','.encode())   
    for c in cities:
        c_code = c.split('|'.encode())[0].decode()
        url3 = url % c_code
        content3 = urllib.request.urlopen(url3).read()
        districts = content3.split(','.encode())        
        for d in districts:
            d_pair = d.split('|'.encode())
            d_code = d_pair[0]
            name = d_pair[1]
            url4 = url % d_code
            content4 = urllib.request.urlopen(url4).read()
            code = content4.split('|'.encode())[1].decode()
            line = "    '%s': '%s',\n" % (name, code)
            result += line
            print(name.decode( ) + ':' + code)
            
result += '}'
f = open('city.py', 'w')
f.write(result)
f.close()

结果:
县:
北京:
海淀:
朝阳:
顺义:
怀柔:
通州:
昌平:
延庆:
丰台:
石景山:
大兴:
房山:
密云:
门头沟:
平谷:
八达岭:
佛爷顶:
汤河口:
密云上甸子:
斋堂:
霞云岭:
上海:
闵行:
宝山:
嘉定:
南汇:
金山:
青浦:
松江:
奉贤:
崇明:
无法打印code的结果,麻烦解答一下,谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即加入

QQ|手机版|Archiver|Crossin的编程教室 ( 苏ICP备15063769号  

GMT+8, 2024-11-25 11:22 , Processed in 0.023555 second(s), 25 queries .

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

回顶部