【问题标题】:Download .xls files from a webpage using Python and BeautifulSoup使用 Python 和 BeautifulSoup 从网页下载 .xls 文件
【发布时间】:2016-01-06 12:10:42
【问题描述】:

我想从本网站下载所有.xls.xlsx.csv到指定文件夹。

https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009

我研究了 mechanize、beautiful soup、urllib2 等。Mechanize 在 Python 3 中不起作用,urllib2 在 Python 3 中也有问题,我寻找了解决方法,但我找不到。所以,我目前正在尝试使用 Beautiful Soup 使其工作。

我找到了一些示例代码并尝试修改它以适应我的问题,如下 -

from bs4 import BeautifulSoup
# Python 3.x
from urllib.request import urlopen, urlretrieve, quote
from urllib.parse import urljoin

url = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009/'
u = urlopen(url)
try:
    html = u.read().decode('utf-8')
finally:
    u.close()

soup = BeautifulSoup(html)
for link in soup.select('div[webpartid] a'):
    href = link.get('href')
    if href.startswith('javascript:'):
        continue
    filename = href.rsplit('/', 1)[-1]
    href = urljoin(url, quote(href))
    try:
        urlretrieve(href, filename)
    except:
        print('failed to download')

但是,当运行此代码时,不会从目标页面提取文件,也不会输出任何失败消息(例如“下载失败”)。

  • 如何使用 BeautifulSoup 从页面中选择 Excel 文件?
  • 如何使用 Python 将这些文件下载到本地文件?

【问题讨论】:

  • 您能描述一下您的代码“不起作用”的原因吗?发布的代码缩进错误,因此根本无法运行。
  • 代码有时只是运行,但从未创建任何文件。关于缩进,我在发帖时道歉,我一定破坏了它,但请放心,当我运行代码时,我确实处理了缩进
  • 我对此问题有一个可行的解决方案,但是问题已关闭,因此我无法再发布它。我已将其作为 Gist 发布在这里 gist.github.com/mfitzp/29522e2ac4057bf01745
  • @mfitzp 非常感谢,这行得通。像你这样的人确保语言永远不会消亡!!!!
  • 添加这几行: 你可以提供mfitzp写的代码的下载位置

标签: python web-scraping beautifulsoup


【解决方案1】:

您的脚本存在的问题是:

  1. url 有一个尾随 /,它会在请求时提供无效页面,而不是列出您要下载的文件。
  2. soup.select(...) 中的 CSS 选择器选择了 div,其属性为 webpartid,该属性在链接文档中的任何位置都不存在。
  3. 您正在加入 URL 并引用它,即使页面中的链接是作为绝对 URL 提供的并且它们不需要引用。
  4. try:...except: 块阻止您查看尝试下载文件时生成的错误。在没有特定异常的情况下使用 except 块是不好的做法,应该避免。

您的代码的修改版本获取正确的文件并尝试下载它们如下:

from bs4 import BeautifulSoup
# Python 3.x
from urllib.request import urlopen, urlretrieve, quote
from urllib.parse import urljoin

# Remove the trailing / you had, as that gives a 404 page
url = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009'
u = urlopen(url)
try:
    html = u.read().decode('utf-8')
finally:
    u.close()

soup = BeautifulSoup(html, "html.parser")

# Select all A elements with href attributes containing URLs starting with http://
for link in soup.select('a[href^="http://"]'):
    href = link.get('href')

    # Make sure it has one of the correct extensions
    if not any(href.endswith(x) for x in ['.csv','.xls','.xlsx']):
        continue

    filename = href.rsplit('/', 1)[-1]
    print("Downloading %s to %s..." % (href, filename) )
    urlretrieve(href, filename)
    print("Done.")

但是,如果您运行此程序,您会注意到引发了 urllib.error.HTTPError: HTTP Error 403: Forbidden 异常,即使该文件可在浏览器中下载。 起初我认为这是一个推荐检查(以防止盗链),但是如果您在浏览器中查看请求(例如 Chrome 开发人员工具),您会注意到 最初的 http:// 请求也在那里被阻止,然后 Chrome 尝试对同一文件发出 https:// 请求。

换句话说,请求必须通过 HTTPS 才能工作(尽管页面中的 URL 是这样说的)。要解决此问题,您需要在使用请求的 URL 之前将 http: 重写为 https:。以下代码将正确修改 URL 并下载文件。我还添加了一个变量来指定输出文件夹,它使用os.path.join添加到文件名中:

import os
from bs4 import BeautifulSoup
# Python 3.x
from urllib.request import urlopen, urlretrieve

URL = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009'
OUTPUT_DIR = ''  # path to output folder, '.' or '' uses current folder

u = urlopen(URL)
try:
    html = u.read().decode('utf-8')
finally:
    u.close()

soup = BeautifulSoup(html, "html.parser")
for link in soup.select('a[href^="http://"]'):
    href = link.get('href')
    if not any(href.endswith(x) for x in ['.csv','.xls','.xlsx']):
        continue

    filename = os.path.join(OUTPUT_DIR, href.rsplit('/', 1)[-1])

    # We need a https:// URL for this site
    href = href.replace('http://','https://')

    print("Downloading %s to %s..." % (href, filename) )
    urlretrieve(href, filename)
    print("Done.")

【讨论】:

  • 解释得很漂亮,我意识到我有很多东西要学。我非常感谢你。
【解决方案2】:

我发现这是一个很好的工作示例,在 Python 2.7 中使用了 BeautifulSoup4requestswget 模块:

import requests
import wget
import os

from bs4 import BeautifulSoup, SoupStrainer

url = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009'

file_types = ['.xls', '.xlsx', '.csv']

for file_type in file_types:

    response = requests.get(url)

    for link in BeautifulSoup(response.content, 'html.parser', parse_only=SoupStrainer('a')):
        if link.has_attr('href'):
            if file_type in link['href']:
                full_path = url + link['href']
                wget.download(full_path)

【讨论】:

    【解决方案3】:
    i tried above code still giving me urllib.error.HTTPError: HTTP Error 403: Forbidden
    
    
    Also tried by adding user agents my modified code
    
    
    import os
    
    from bs4 import BeautifulSoup
    # Python 3.x
    from urllib.request import Request,urlopen, urlretrieve
    
    headers = {'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'}
    URL = Request('https://www.rbi.org.in/scripts/bs_viewcontent.aspx?Id=2009', headers=headers)
    
    #URL = 'https://www.rbi.org.in/scripts/bs_viewcontent.aspx?Id=2009'
    
    OUTPUT_DIR = 'E:\python\out'  # path to output folder, '.' or '' uses current folder
    
    u = urlopen(URL)
    try:
        html = u.read().decode('utf-8')
    finally:
        u.close()
    
    soup = BeautifulSoup(html, "html.parser")
    for link in soup.select('a[href^="http://"]'):
        href = link.get('href')
        if not any(href.endswith(x) for x in ['.csv','.xls','.xlsx']):
            continue
    
        filename = os.path.join(OUTPUT_DIR, href.rsplit('/', 1)[-1])
    
        # We need a https:// URL for this site
        href = href.replace('http://','https://')
    
        print("Downloading %s to %s..." % (href, filename) )
        urlretrieve(href, filename)
        print("Done.")
    

    【讨论】:

      【解决方案4】:

      这对我来说效果最好......使用 python3

      import os
      import urllib
      
      from bs4 import BeautifulSoup
      # Python 3.x
      from urllib.request import urlopen, urlretrieve
      from urllib.error import HTTPError
      
      URL = 'https://www.rbi.org.in/Scripts/bs_viewcontent.aspx?Id=2009'
      OUTPUT_DIR = ''  # path to output folder, '.' or '' uses current folder
      
      u = urlopen(URL)
      try:
          html = u.read().decode('utf-8')
      finally:
          u.close()
      
      soup = BeautifulSoup(html, "html.parser")
      for link in soup.select('a[href^="http://"]'):
          href = link.get('href')
      if not any(href.endswith(x) for x in ['.csv','.xls','.xlsx']):
          continue
      
      filename = os.path.join(OUTPUT_DIR, href.rsplit('/', 1)[-1])
      
      # We need a https:// URL for this site
      href = href.replace('http://','https://')
      
      try:
          print("Downloading %s to %s..." % (href, filename) )
          urlretrieve(href, filename)
          print("Done.")
      except urllib.error.HTTPError as err:
          if err.code == 404:
              continue
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-09-13
        • 1970-01-01
        • 2019-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-09
        • 1970-01-01
        相关资源
        最近更新 更多