Как переименовать файл с текстом из определенного HTML-элемента при использовании urllib.request и BeautifulSoup для загрузки файлов - PullRequest
0 голосов
/ 10 июля 2019

У меня есть алгоритм, который загружает статьи в формате PDF с urllib.request и BeautifulSoup (Python 3.6):

import requests as r
from bs4 import BeautifulSoup as soup
import os
import urllib.request

#make a list of all web pages' urls
webpages=[]
for i in range(9):
    root_url = 'xxx.com/articles/page'+ str(i)
    webpages.append(root_url)

#make a list of PDF links
pdf_links = []
for item in webpages:
    headers = {'User-Agent': 'Mozilla/5.0'}
    data = r.get(item, headers=headers)
    page_soup = soup(data.text, 'html.parser')
    links = [span.attrs['href'] for span in page_soup.find_all('a', href = True)] 
    for link in links:
        link_string = str(link)
        if link_string.endswith('pdf'):
            pdf_links.append(link_string)

    #download the files
    for pdf_link in pdf_links:
        save_to = os.path.basename(pdf_link.strip())
        urllib.request.urlretrieve(pdf_link.strip(), save_to)

Мне нужно переименовать каждую загруженную статью PDF с названием статьи, которая хранится в определенном div классе:

<div class="article article title">
<h2>The Disaster of Deforestation</h2>
</div>

Существует более крупный div, в котором хранится как заголовок статьи, так и соответствующая ссылка PDF:

<div article-id="1741" class="online article_row_view">
<div class="article article title">
<h2>The Disaster of Deforestation</h2>
</div>
<span class="file-pdf"> <a href="xsdf.pdf" title="BowenA.pdf">PDF</a></span>
</div>

Я понятия не имею, как автоматически переименовывать файлы, тем более с определенным элементом HTML. Любая помощь будет оценена!

1 Ответ

1 голос
/ 10 июля 2019

Вот полное решение, которое просматривает все страницы навигации и загружает все PDF-файлы для вас:

import requests
from bs4 import BeautifulSoup, Tag, Comment, NavigableString
from pathlib import Path
from urllib.parse import urljoin

BASE_URL = 'https://cross-currents.berkeley.edu/archives'

def make_soup(url: str) -> BeautifulSoup:
    res = requests.get(url, headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0'})
    res.raise_for_status()
    html = res.text
    soup = BeautifulSoup(html, 'html.parser')
    return soup

def extract_articles(soup: BeautifulSoup) -> list:
    articles = []
    for result in soup.select('.node--view-mode-search-result'):
        author = result.select_one('.field--name-field-citation-authors').text.strip()
        date = result.select_one('.field--name-field-issue-date').text.strip()
        title = result.select_one('.field-name-node-title').text.strip()
        journal = result.find('em', recursive=False).text.strip()
        pdf_url = result.select_one('a[href*=".pdf"]')['href']
        articles.append({
            'author': author,
            'date': date,
            'title': title,
            'journal': journal,
            'pdf_url': pdf_url,
        })
    return articles

def make_safe_filename(text: str) -> str:
    """convert forbidden chars to underscores"""
    return ''.join(c if (c.isalnum() or c.isspace()) else '_' for c in text).strip('_ ')


def get_next_page_url(soup: BeautifulSoup) -> str:
    try:
        path = soup.select_one('.pager a[rel="next"]')['href']
        return urljoin(BASE_URL, path)
    except (TypeError, KeyError):
        return None

def download_file(url: str, filename: str) -> str:
    with requests.get(url, stream=True) as res, open(filename, 'wb') as f:
        res.raise_for_status()
        for chunk in res.iter_content(chunk_size=8192): 
            if chunk:
                f.write(chunk)
    return filename

def scrape_archive():
    save_dir = Path(r'd:\downloads')
    save_dir.mkdir(exist_ok=True, parents=True)

    url = 'https://cross-currents.berkeley.edu/archives?author=&title=&type=onlinearticle&issue=All&region=All&page=0'
    while True:
        soup = make_soup(url)
        articles = extract_articles(soup)

        for a in articles:
            pdf_url = a['pdf_url']
            filename = make_safe_filename(a['title'])
            save_path = str(save_dir / (filename + '.pdf'))
            print('Downloading:', a['title'])
            download_file(pdf_url, save_path)
            print('Finished')

        # go to next page if exists
        next_url = get_next_page_url(soup)
        if not next_url:
            break
        url = next_url
        print('Moving to next page', url)

scrape_archive()

Здесь я использовал только заголовок для генерации pdf-файла, но вы можете смешивать и комбинировать journal, date, author и т. Д. Для создания лучшего имени файла.
Также не забудьте изменить save_dir по своему вкусу.

...