【问题标题】:Download csvs to desktop from csv links从 csv 链接将 csvs 下载到桌面
【发布时间】:2019-05-30 10:34:14
【问题描述】:

问题:

不知道 google fu 是否再次让我失望,但我无法从 url 列表中下载 csvs。我使用requestsbs4 来收集网址(最终列表是正确的) - 请参阅下面的流程以获取更多信息。

然后我按照此处给出的答案之一使用urllib 下载:Trying to download data from URL with CSV File,以及其他一些用于下载 csvs 的 stackoverflow python 答案。

目前我被困在一个

HTTP 错误 404:未找到

(下面的堆栈跟踪来自上次尝试传递 User-Agent)

----> 9 f = urllib.request.urlopen(req)
     10 print(f.read().decode('utf-8'))
     #other lines

--> 650         raise HTTPError(req.full_url, code, msg, hdrs, fp)
    651 
    652 class HTTPRedirectHandler(BaseHandler):

HTTPError: HTTP Error 404: Not Found

我在这里尝试了添加 User-Agent: Web Scraping using Python giving HTTP Error 404: Not Found 的解决方案,尽管我预计会出现 403 而不是 404 错误代码 - 但似乎适用于许多 OP。

这仍然失败并出现同样的错误。我很确定我可以通过简单地使用 selenium 并将 csv url 传递给 .get 来解决这个问题,但我想知道我是否可以单独使用请求来解决这个问题。


大纲:

我访问了这个页面:

https://digital.nhs.uk/data-and-information/publications/statistical/patients-registered-at-a-gp-practice

我获取所有每月版本的链接,例如Patients Registered at a GP Practice May 2019,然后我访问每个页面并获取其中的所有 csv 链接。

我循环尝试下载文件的 filename:download_url 对的最终字典。


问题:

谁能看到我做错了什么或者如何解决这个问题,这样我就可以在不求助于 selenium 的情况下下载文件?我也不确定实现这一点的最有效方法 - 也许实际上根本不需要 urllib,只需要请求就足够了吗?


Python:

没有用户代理:

import requests
from bs4 import BeautifulSoup as bs
import urllib

base = 'https://digital.nhs.uk/'
all_files = []

with requests.Session() as s:
    r = s.get('https://digital.nhs.uk/data-and-information/publications/statistical/patients-registered-at-a-gp-practice')
    soup = bs(r.content, 'lxml')
    links = [base + item['href'] for item in soup.select('.cta__button')]

    for link in links:
        r = s.get(link)
        soup = bs(r.content, 'lxml')
        file_links = {item.text.strip().split('\n')[0]:base + item['href'] for item in soup.select('[href$=".csv"]')}
        if file_links:
            all_files.append(file_links)  #ignore empty dicts as for some months there is no data yet
        else:
            print('no data : ' + link)

all_files = {k: v for d in all_files for k, v in d.items()}  #flatten list of dicts to single dict


path = r'C:\Users\User\Desktop'

for k,v in all_files.items():
    #print(k,v)
    print(v)
    response = urllib.request.urlopen(v)
    html = response.read()

    with open(path + '\\' + k + '.csv', 'wb') as f:
        f.write(html)
    break  #as only need one test case

添加用户代理进行测试:

req = urllib.request.Request(
    v, 
    data=None, 
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'
    }
)

f = urllib.request.urlopen(req)
print(f.read().decode('utf-8'))

【问题讨论】:

  • 使用 Fiddler 之类的工具来检查您发出的请求是否 (a) 正确(您是否以某种方式修改了文件名?)并且 (b) 与您对同一文件发出的请求相匹配通过浏览器。我不认为 User-Agent 标头在这种情况下是相关的。我选择了files.digital.nhs.uk/0D/65E837/…(“在 GP 诊所注册的患者 - 2019 年 5 月:单岁(GP 诊所 - 男性)”),并且能够通过 Fiddlers Replay 下载除 Host 之外的每个标题> 补发和编辑
  • @Rob 谢谢。我也不认为用户代理是给定错误代码的相关部分,但想展示我的努力。我会看看开发工具是否捕获了我可以使用的任何东西。我通过将文件名粘贴到浏览器中进行了检查,并且下载正常。
  • 但没有检查连接! @Rob

标签: python-3.x csv web-scraping python-requests


【解决方案1】:

查看值,它向我展示了您的链接

https://digital.nhs.uk/https://files.digital.nhs.uk/publicationimport/pub13xxx/pub13932/gp-reg-patients-04-2014-lsoa.csv

我想你想删除base +,所以使用这个:

file_links = {item.text.strip().split('\n')[0]:item['href'] for item in soup.select('[href$=".csv"]')}

代替:

file_links = {item.text.strip().split('\n')[0]:base + item['href'] for item in soup.select('[href$=".csv"]')}

编辑:完整代码:

import requests
from bs4 import BeautifulSoup as bs

base = 'https://digital.nhs.uk/'
all_files = []

with requests.Session() as s:
    r = s.get('https://digital.nhs.uk/data-and-information/publications/statistical/patients-registered-at-a-gp-practice')
    soup = bs(r.content, 'lxml')
    links = [base + item['href'] for item in soup.select('.cta__button')]

    for link in links:
        r = s.get(link)
        soup = bs(r.content, 'lxml')
        file_links = {item.text.strip().split('\n')[0]:item['href'] for item in soup.select('[href$=".csv"]')}
        if file_links:
            all_files.append(file_links)  #ignore empty dicts as for some months there is no data yet
        else:
            print('no data : ' + link)

all_files = {k: v for d in all_files for k, v in d.items()}  #flatten list of dicts to single dict

path = 'C:/Users/User/Desktop/'

for k,v in all_files.items():
    #print(k,v)
    print(v)
    response = requests.get(v)
    html = response.content

    k = k.replace(':', ' -')
    file = path + k + '.csv'

    with open(file, 'wb' ) as f:
        f.write(html)
    break  #as only need one test case

【讨论】:

  • 谢谢。我下载了一个未知的文件类型。你能明白为什么我的 .csv 如果不工作吗?如果需要,很高兴询问后续情况。以结尾传递的示例下载为 C:\Users\User\Desktop\Patients Registered at a GP Practice - May 2019: Totals (GP practice-all persons).csv
  • 不确定您正在使用什么操作系统,但我在 Windows 上,您不能在文件名中包含 :。检查上面的解决方案,我放置了似乎对我有用的整个代码。我所做的只是将 k 变量中的 : 替换为 `-`。注意不要在路径中替换它,因为: 是必需的
  • 效果很好。谢谢你。我对 python 还很陌生——你知道任何关于哪种 csv 下载方法更有效的资源吗? urllib 在我对下载进行的研究中似乎很常见。
  • 自去年年底以来,我最依赖 css /html/xhr 知识,并且是其他语言的抓取。可悲的是我的python不是很先进。
  • 嗯,好的。您的解决方案总是那么好,所以我只是假设您已经这样做了一段时间!继续努力!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-31
  • 1970-01-01
相关资源
最近更新 更多