【问题标题】:Why would python37 stop downloading a url?为什么 python37 会停止下载 url?
【发布时间】:2022-01-05 22:58:27
【问题描述】:

这个程序已经运行了多年。我好几个月没用了,现在它不会下载必要的文件了。我在 Windows 7 上使用 python37。 将字节解码为字符串还有一个新问题。

这是相关的子程序,带有注释:

import urllib
import urllib.request
import socket
import sys, os
# ---
def geturl(url, stk):   # reads a web page into a string
    print("at180: into geturl with url=",url)

#Here's the url I passed it
#https://finance.yahoo.com/quote/qqq/history?period1=1480204800&period2=1637971200&interval=1mo&filter=history&frequency=1mo

# it returns a 404 error, but works fine if pasted into Chrome browser, or when used in a perl call to get. 

# I tried a simpler one: https://finance.yahoo.com/quote/QQQ/history?p=QQQ
    url = "https://finance.yahoo.com/quote/QQQ/history?p=QQQ" 
# it also returned a 404 error

#I tried one even simpler
    url = "https://finance.yahoo.com" 
# this one does not return a 404 error but has conversion error from byte to str

    try:
        junk = urllib.request.urlopen(url, timeout=4).read()
    except urllib.error.URLError as e:
        print("URLError with ",stk," = ", e) 
        return("Error")
    except socket.timeout as e:
        return("Timeout")
    page = str( junk, encoding='utf8' ) # convert from type 'bytes' to type 'str

# error here with the simple url: 
"UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte "

    print("\nat197, returning page")
    pause()
    return(page)

为什么 urllib.request.urlopen 找不到一个如果传递给 Chrome 浏览器可以正常工作的 url?

如果我除了基本 url 地址之外的所有内容都省略了,为什么它会找到它?

如何打印出字节字符串“垃圾”以便阅读? 它似乎有很多非十六进制字符。

网页不再使用 UTF-8 了吗?如果是这样,我应该指定什么编码?

【问题讨论】:

  • 您是否尝试过使用 requests 库? (只是看看你能不能从那个网址得到一些东西)
  • 很有可能,finance.yahoo.com 现在正在阻止基于用户代理的 python 请求。
  • 如果您还有其他问题,请随时在下方回复 - 如果您认为您的问题已得到解答,您可以接受带有复选标记的答案,它会在网站上显示为已回答。

标签: python download file-conversion


【解决方案1】:

与 Python 的变化无关,但看起来用于为您提供服务的页面没有经过 gzip 压缩,而现在是。

这是一个在没有外部库(如 requests)的情况下工作的示例:

import urllib.request
import urllib.error
from io import BytesIO
import gzip

url = "https://finance.yahoo.com"
try:
    request = urllib.request.Request(url)
    request.add_header('Accept-encoding', 'gzip')
    response = urllib.request.urlopen(request)
    if response.info().get('Content-Encoding') == 'gzip':
        buf = BytesIO(response.read())
        with gzip.GzipFile(fileobj=buf) as f:
            content = f.read()
    else:
        content = response.read()
    page = content.decode()
    print(page)
except (urllib.error.URLError) as e:
    print("URLError with ",url," = ", e)

我还用str.decode() 替换了您的str() 演员表(因为它是UTF-8,所以默认是可以的)。

您表示您在https://finance.yahoo.com/quote/QQQ/history?p=QQQ 等页面上仍然收到 404。这是正确的,也是雅虎网站发生变化的结果。雅虎不喜欢你刮他们的网页(他们的条款可能说你不应该)。因此它会检查它是发出请求的脚本还是常规浏览器。

你可以让 Python 撒谎:

    request.add_header('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36')

如果您添加它,请求将起作用。也就是说,直到雅虎进一步收紧规则并让你做出更多改变。

这就是为什么在抓取前端页面的基础上构建一个需要更长时间工作的应用程序通常不是一个好主意。相反,基于受支持的 API 编写脚本(这可能意味着获取 API 密钥并可能需要付费,如果您经常使用它)。

【讨论】:

  • 我不认为这是雅虎的问题,因为我在 Perl 中使用 LWP::Simple get 抓取这些页面没有问题。多年来我一直在这样做,雅虎几乎没有窥视过。而且我认为它不会返回一个压缩文件,因为它只是说它找不到我正在寻找的文件。但是感谢您使用解码的建议。我以前从未遇到过。另外,我曾经使用 Yahoo API,但几年前他们停止了它。而且我认为他们希望人们只是抓取页面,因为当它起作用时,他们会提供一个大的 JSON 文件,而不是 html。
  • 您忽略了这样一个事实,即 Perl 可能一直能够处理 gzip 压缩的内容并欺骗代理标头(这是常见的做法,让那些反对抓取的人感到沮丧)。你说你的代码过去可以工作的事实几乎可以肯定雅虎确实改变了它的做法——这是有道理的,几乎每个严肃的企业都会这样做。我敢赌钱。如果您必须证明自己相信它,您可以随时下载您曾经使用的任何版本的 Python 并尝试 - Python 支持并排安装多个。
猜你喜欢
  • 1970-01-01
  • 2013-01-31
  • 1970-01-01
  • 2015-07-30
  • 1970-01-01
  • 2013-10-25
  • 2012-10-07
  • 2021-04-25
  • 2018-08-03
相关资源
最近更新 更多