ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

urllib.request.urlopen(url)不能两次.read()?

2022-02-04 14:03:42  阅读:148  来源: 互联网

标签:utf urlopen request urllib read url print response


问题描述:

笔者在初学Python爬虫时,用到 urllib.request.urlopen 获取百度搜索页面 (http://www.baidu.com) 上的信息。

首先,访问百度并获取网页信息,将信息保存在 response 中。代码如下:

from urllib.request import urlopen
url = r'http://www.baidu.com'
response = urlopen(url)

然后,调用 .read() 看一下 response 的内容,发现 charset=utf-8,于是用 utf-8 解码。代码如下:

print(response.read())

''' 

结果:
b'<!DOCTYPE html><!--STATUS OK-->\n\n\n    
<html><head><meta http-equiv="Content-Type" content="text/html;
charset=utf-8">
......'

'''

最后,用 utf-8 解码 response 的内容,并把解码后的内容保存到 百度.html 中。代码如下:

with open(r'百度.html','w') as f:
    f.write(response.read().decode('utf-8'))

然而,打开 百度.html 后却发现其一片空白???

现在打印一下 response.read().decode(‘utf-8’),居然也是空的???

print(response.read().decode('utf-8'))
''' 结果:b'' '''

探索原因:

首先,检查一下 response.read() 的内容是从哪一步开始变为空的。代码如下:

from urllib.request import urlopen
url = r'http://www.baidu.com'
response = urlopen(url)
print('1','-'*100,'\n',response.read(),sep='')
print('2','-'*100,'\n',response.read(),sep='')
with open(r'百度.html','w') as f:
    print('3','-'*100,'\n',response.read(),sep='')
    f.write(response.read().decode('utf-8'))
print('4','-'*100,'\n',response.read(),sep='')

'''
结果:
1----------------------------------------------------------------------------------------------------
b'<!DOCTYPE html><!--STATUS OK-->\n\n\n    <html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8">......
2----------------------------------------------------------------------------------------------------
b''
3----------------------------------------------------------------------------------------------------
b''
4----------------------------------------------------------------------------------------------------
b''
'''

发现,在 response.read() 写入 百度.html 前, response.read() 就已经变为空的了,即 response 的第一次 .read() 一切顺利,但是第二次 .read() 就变为空的了。

于是,我们探索一下 response.read()。
通过查看帮助文档,发现response.read 只有一个参数 amt:当 amt=None/负数 时,会读取所有字节;当 amt=正数k 时,会读取 k 个字节。

from urllib.request import urlopen
url = r'http://www.baidu.com'
response = urlopen(url)
print('1','-'*100,'\n',response.read(amt=20),sep='')
print('2','-'*100,'\n',response.read(amt=40),sep='')
response = urlopen(url)
print('3','-'*100,'\n',response.read(amt=60),sep='')
'''
结果:
1----------------------------------------------------------------------------------------------------
b'<!DOCTYPE html><!--S'
2----------------------------------------------------------------------------------------------------
b'TATUS OK-->\n\n\n    <html><head><meta http'
3----------------------------------------------------------------------------------------------------
b'<!DOCTYPE html><!--STATUS OK-->\n\n\n    <html><head><meta http'
'''

可以看到,在第一步解读 response 的前 20 个字节后,第二步解读的 40 个字节,是指 response 的第 21-60 个字节,而非前 40 个。第三步重新获取 response ,并解读其前 60 个字节,刚好是 第一步 与 第二步 的拼接。

因此,response.read() 解读了 response 的所有字节,再次使用 response.read() 时才会得到空的结果。


解决方案:

确定解码类型时,可以先打开网页源码查看 charset=utf-8,然后直接将 response.read().decode(‘utf-8’) 写入 百度.html。代码如下:

from urllib.request import urlopen
url = r'http://www.baidu.com'
response = urlopen(url)
with open(r'百度.html','w') as f:
    f.write(response.read().decode('utf-8'))

如有不当之处,烦请指出!

标签:utf,urlopen,request,urllib,read,url,print,response
来源: https://blog.csdn.net/weixin_44548627/article/details/122782283

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有