Загрузите csvs на рабочий стол по ссылкам csv - PullRequest
1 голос
/ 30 мая 2019

Проблема:

Не знаю, повторяет ли меня Google-фу, но я не могу загрузить CSV-файлы из списка URL-адресов.Я использовал requests и bs4 для сбора URL-адресов (окончательный список верен) - для получения дополнительной информации см. Процесс ниже.

Затем я следовал одному из приведенных здесь ответов, используя urllib для загрузки: Попытка загрузки данных из URL с помощью файла CSV , а также ряда других ответов python для stackoverflow для загрузки csvs.

В настоящее время я застрял с

Ошибка HTTP 404: не найдено

(ниже трассировки стека от последней попытки, где проходил пользователь-агент)

----> 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 с использованием Python, выдающий ошибку HTTP 404: не найдено , хотя я ожидал бы код ошибки 403, а не 404 - но, похоже, сработал для ряда OP.

Это все ещене удалось с той же ошибкой.Я почти уверен, что смогу решить эту проблему, просто используя selenium и передав URL-адреса csv в .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 пар, пытающихся загрузить файлы.


Вопрос:

Кто-нибудь может увидеть, что я делаю неправильно или как это исправить, чтобы я мог скачивать файлы, не прибегая к селену?Я также не уверен в самом эффективном способе сделать это - возможно, urllib на самом деле вообще не требуется, и достаточно просто запросов?


Python:

Без user-agent:

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

Тест с добавлением User-Agent:

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'))

1 Ответ

1 голос
/ 30 мая 2019

глядя на значения, он показывает мне ваши ссылки

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
...