Вывод результатов очистки в несколько CSV-файлов с помощью python, BeautifulSoup, pandas?

#python #pandas #csv #web-scraping #beautifulsoup

#python #pandas #csv #веб-очистка #beautifulsoup

Вопрос:

Я собираю ссылки с нескольких страниц при нескольких поисковых запросах и хочу вывести очищенные результаты в несколько файлов .csv. В таблице показан файл .csv, в котором перечислены как мои исходные URL-адреса, так и желаемые имена выходных файлов:

url outputfile
https://www.marketresearch.com/search/results.asp?categoryid=230amp;qtype=2amp;publisher=IDCsamp;datepub=0amp;submit2=Search outputPS1xIDC.csv
https://www.marketresearch.com/search/results.asp?categoryid=90amp;qtype=2amp;publisher=IDCamp;datepub=0amp;submit2=Search outputPS2xIDC.csv
https://www.marketresearch.com/search/results.asp?categoryid=233amp;qtype=2amp;publisher=IDCamp;datepub=0amp;submit2=Search outputPS3xIDC.csv
https://www.marketresearch.com/search/results.asp?categoryid=169amp;qtype=2amp;publisher=IDCamp;datepub=0amp;submit2=Search outputPS4xIDC.csv

Теперь, с помощью приведенного ниже кода, мне удалось последовательно прочитать URL-адреса, и остальной код также работает хорошо (когда я указываю выходное имя файла напрямую). Однако он выводит только последнюю из 4 страниц в списке, поэтому каждый раз перезаписывает результат. Что я на самом деле хочу для этого, так это выводить результаты с первого URL-адреса на первый выходной файл, со второго на второй и т.д. (Конечно, мой фактический список исходных URL-адресов намного длиннее, чем эти 4).

Пожалуйста, помогите, особенно с последней строкой, так как очевидно, что просто написать [outputs] там не работает.

 import requests
from bs4 import BeautifulSoup
import pandas as pd
import csv

with open('inputs.csv', newline='') as csvfile:
    reader = csv.DictReader(csvfile)
    urls = [row["url"] for row in reader]
    outputs = [row["outputfile"] for row in reader]

    data = []

    for url in urls:

        def scrape_it(url):
            page = requests.get(url, headers={'Cookie': 'ResultsPerPage=100'})
            soup = BeautifulSoup(page.text, 'html.parser')
            nexturl = soup.find_all(class_="standardLinkDkBlue")[-1]['href']
            stri = soup.find_all(class_="standardLinkDkBlue")[-1].string
            reports = soup.find_all("tr", {"class": ["SearchTableRowAlt", "SearchTableRow"]})

            for report in reports:
                data.append({
                    'title': report.find('a', class_='linkTitle').text,
                    'price': report.find('div', class_='resultPrice').text,
                    'date_author': report.find('div', class_='textGrey').text.replace(' | published by: TechNavio', ''),
                    'detail_link': report.a['href']
                })

            if 'next' not in stri:
                print("All pages completed")
            else:
                scrape_it(nexturl)


    scrape_it(url)
    myOutput = pd.DataFrame(data)
    myOutput.to_csv([outputs], header=False) #works (but only for the last url) if instead of [outputs] I have f'filename.csv'
 

Ответ №1:

У меня нет Pandas, и я действительно не хочу запускать ваш ввод, но пара вещей выскакивает у меня, когда я смотрю на ваш код:

  1. Похоже, вы не перебираете url и не output объединяете. Похоже, что вы перебираете все URL-адреса, а затем после всех этих циклов вы пишете один раз.
  2. Аналогично, data просто добавляя и добавляя данные таблицы HTML, они никогда не сбрасываются для каждого отдельного URL.

Не имея возможности запустить это, я рекомендую что-то вроде этого. Очистка полностью инкапсулирована и отделена от цикла, и поэтому теперь вы можете более четко видеть поток входных и выходных данных:

 import requests
from bs4 import BeautifulSoup
import csv
import pandas as pd


def scrape_it(url, data):
    page = requests.get(url, headers={'Cookie': 'ResultsPerPage=100'})
    soup = BeautifulSoup(page.text, 'html.parser')
    nexturl = soup.find_all(class_="standardLinkDkBlue")[-1]['href']
    stri = soup.find_all(class_="standardLinkDkBlue")[-1].string
    reports = soup.find_all("tr", {"class": ["SearchTableRowAlt", "SearchTableRow"]})

    for report in reports:
        data.append({
            'title': report.find('a', class_='linkTitle').text,
            'price': report.find('div', class_='resultPrice').text,
            'date_author': report.find('div', class_='textGrey').text.replace(' | published by: TechNavio', ''),
            'detail_link': report.a['href']
        })

    if 'next' in stri:
        data = scrape_it(nexturl, data)
    
    return data


with open('inputs.csv', newline='') as csvfile:
    reader = csv.DictReader(csvfile)
    urls = [row["url"] for row in reader]
    outputs = [row["outputfile"] for row in reader]

    for (url, output) in zip(urls, outputs):  # work on url and output together
        data = scrape_it(url, [])
        myOutput = pd.DataFrame(data)
        myOutput.to_csv(output, header=False)
 

Комментарии:

1. Это делает именно то, что мне было нужно! Удивительно, что вы можете сделать это, даже не запуская этот код! Большое вам спасибо!

2. Добро пожаловать! У меня был действительно хороший учитель, который подчеркивал умение читать код, и я мог прочитать, что структура была отключена. 🙂 Приветствия!

3. О, подождите! Я только что понял, что это не сработает для страниц с более чем 100 результатами.

4. большое спасибо за дальнейшую работу над этим. Однако я не уверен, что происходит сейчас — он завершается с кодом выхода 0, но не создает никаких CSV-файлов с какими-либо данными. Поэтому завтра я просмотрю и проверю его построчно, чтобы увидеть, на каком этапе может возникнуть проблема (поскольку отладчик ничего не находит).

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