Как написать код для чтения выходного файла, чтобы выяснить, как далеко он зашел в очистке веб-сайта, а затем начать с того места, где он остановился - PullRequest
0 голосов
/ 02 июля 2019

Я пишу программу для очистки заголовка статьи, даты и основного текста из каждой статьи в архиве этого сайта и экспорта в файл CSV. Веб-сайт, кажется, блокирует меня в какой-то момент, и я получаю эту ошибку: HTTPError: Служба недоступна.

Я считаю, что это потому, что я пытаюсь зайти на их сайт слишком много раз за короткий промежуток времени. Я хочу, чтобы мой код мог прочитать, где произошла ошибка, и узнать, где она остановилась.

Я пытался добавить задержки для задержки через 2 секунды после просмотра 10 статей. Я также пробовал случайные задержки после каждых десяти статей. Я мог бы добавить более длительные задержки, но я бы хотел, чтобы код мог работать там, где он чувствовал себя надежным.

from bs4 import BeautifulSoup
from urllib.request import urlopen
import csv
from time import sleep
from random import randint

csvfile = "C:/Users/k/Dropbox/granularitygrowth/Politico/pol.csv"
with open(csvfile, mode='w', newline='', encoding='utf-8') as pol:
    csvwriter = csv.writer(pol, delimiter='~', quoting=csv.QUOTE_MINIMAL)
    csvwriter.writerow(["Date", "Title", "Article"])

    #for each page on Politico archive
    for p in range(0,412):
        url = urlopen("https://www.politico.com/newsletters/playbook/archive/%d" % p)
        content = url.read()

        #Parse article links from page
        soup = BeautifulSoup(content,"lxml")
        articleLinks = soup.findAll('article', attrs={'class':'story-frag format-l'})

        #Each article link on page
        for article in articleLinks:
            link = article.find('a', attrs={'target':'_top'}).get('href')

            #Open and read each article link
            articleURL = urlopen(link)
            articleContent = articleURL.read()

            #Parse body text from article page
            soupArticle = BeautifulSoup(articleContent, "lxml")

            #Limits to div class = story-text tag (where article text is)
            articleText = soupArticle.findAll('div', attrs={'class':'story-text'})
            for div in articleText:

                #Find date
                footer = div.find('footer', attrs={'class':'meta'})
                date = footer.find('time').get('datetime')
                print(date)

                #Find title
                headerSection = div.find('header')
                title = headerSection.find('h1').text
                print(title)

                #Find body text
                textContent = ""
                bodyText = div.findAll('p')
                for p in bodyText:
                    p_string = str(p.text)
                    textContent += p_string + ' '
                print(textContent)

                #Adds data to csv file
                csvwriter.writerow([date, title, textContent])

        time.sleep(randint(3,8))

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

1 Ответ

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

Вы можете сосчитать количество статей, которые вы сохранили в CSV, и разделить его на 10 (page = 1 + records // 10 (+1 для первой страницы)), чтобы получить последнюю страницу, на которой вы были.

Я изменил ваш код следующим образом:

import csv
import time
from random import randint
from urllib.request import urlopen

from bs4 import BeautifulSoup

HEADERS = ["Date", "Title", "Article"]


def count_rows(csv_path: str) -> int:
    with open(csv_path) as f:
        reader = csv.DictReader(f)
        return len(list(reader))


def write_articles(csv_path: str, articles: list):
    # note the append mode, write mode would delete everything and start fresh
    with open(csv_path, 'a', encoding='utf-8', newline='') as f:
        writer = csv.DictWriter(f,
                                quoting=csv.QUOTE_MINIMAL,
                                fieldnames=HEADERS)
        writer.writerows(articles)


def init_csv(csv_path: str):
    with open(csv_path, 'w', encoding='utf-8', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=HEADERS, quoting=csv.QUOTE_MINIMAL)
        writer.writeheader()


def get_page_soup(url: str) -> BeautifulSoup:
    response = urlopen(url)
    html = response.read()

    soup = BeautifulSoup(html, "lxml")
    return soup


def scrape_article(url: str) -> dict:
    article_soup = get_page_soup(url)

    # Limits to div class = story-text tag (where article text is)
    story_el = article_soup.select_one('.story-text')

    # find date
    date = story_el.select_one('.timestamp time')['datetime']

    # find title
    title = story_el.find('h1').text

    # find body text
    article_text = ''
    for p in story_el.find_all('p'):
        article_text += p.text + ' '

    return {
        'Title': title,
        'Date': date,
        'Article': article_text
    }


def main():
    csvfile = "test.csv"

    try:
        record_count = count_rows(csvfile)
    except FileNotFoundError:
        init_csv(csvfile)
        print('Initialized CSV file')
        record_count = 0

    article_per_page = 10
    page = 1 + record_count // article_per_page

    print('Continuing from page', page)

    articles = []
    for p in range(page, 413):
        url = "https://www.politico.com/newsletters/playbook/archive/%d" % p
        soup = get_page_soup(url)
        article_links = soup.select('article.story-frag.format-l')

        # Each article link on page
        for article in article_links:
            link = article.select_one('a[target=_top]')['href']
            scraped_article = scrape_article(link)
            print(scraped_article)
            articles.append(scraped_article)

        write_articles(csvfile, articles)
        print('Finished page', p)
        time.sleep(randint(3, 8))


if __name__ == '__main__':
    main()

это дает такой вывод:

Finished page 48
{'Title': 'Playbook: Scalise takes several Republicans to ...
{'Title': 'Playbook: Four unfolding events that show the  ...
{'Title': 'Playbook: Texas kicks off primary season, as D ...
{'Title': 'Playbook: The next gen: McCarthy and Crowley’s ...
{'Title': 'INSIDE THE GRIDIRON DINNER: What Trump said an ...
{'Title': 'DEMS spending millions already to boost vulner ...
{'Title': 'Playbook: Inside the Republican super PAC mone ...
{'Title': 'Playbook: Who would want to be White House com ...
{'Title': "Playbook: Jared Kushner's bad day", 'Date': '2 ...
{'Title': 'Playbook: Gun control quickly stalls in the Se ...
Finished page 49
...