#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, и я действительно не хочу запускать ваш ввод, но пара вещей выскакивает у меня, когда я смотрю на ваш код:
- Похоже, вы не перебираете
url
и неoutput
объединяете. Похоже, что вы перебираете все URL-адреса, а затем после всех этих циклов вы пишете один раз. - Аналогично,
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. Привет, нет проблем. Мне нравится пытаться помочь 🙂 Я не уверен, каков ваш уровень комфорта во всем этом. Я пошел дальше и изложил эту суть , чтобы попытаться объяснить, как обрабатывать очистку, пока не останется ничего, что можно было бы очистить. Может быть, это будет понятнее, если взять из общей картины, с помощью простых примеров.