#python-3.x #web-scraping #beautifulsoup #pagination #python-requests-html
#python-3.x #очистка веб-страниц #beautifulsoup #разбивка на страницы #python-запросы-html
Вопрос:
Краткие сведения
Я работаю над своим проектом колледжа по управлению цепочками поставок и хочу анализировать ежедневные публикации на веб-сайте, чтобы анализировать и документировать спрос отрасли на услуги / продукты. Конкретная страница, которая меняется каждый день и с разным количеством контейнеров и страниц :
Bacground
Код генерирует csv-файл (не обращайте внимания на заголовки) путем очистки HTML-тегов и документирования точек данных. Пытался использовать цикл ‘for’, но код по-прежнему сканирует только первую страницу.
Уровень знаний Python: новичок, изучите «трудный путь» через YouTube и поиск в Google. Нашел пример, который сработал для моего уровня понимания, но возникли проблемы с объединением различных решений людей.
Код на данный момент
импортируйте bs4 из urllib.request импортируйте urlopen как uReq из bs4 импортируйте BeautifulSoup как soup
проблема начинается здесь
for page in range (1,3):my_url = 'https://buyandsell.gc.ca/procurement-data/search/site?f[0]=sm_facet_procurement_data:data_data_tender_noticeamp;f[1]=dds_facet_date_published:dds_facet_date_published_today'
uClient = uReq(my_url)
page_html = uClient.read()
uClient.close()
page_soup = soup(page_html, "html.parser")
containers = page_soup.findAll("div",{"class":"rc"})
в этой части не выполняется запись в дополнение к существующим позициям
filename = "BuyandSell.csv"
f = open(filename, "w")
headers = "Title, Publication Date, Closing Date, GSIN, Notice Type, Procurement Entityn"
f.write(headers)
for container in containers:
Title = container.h2.text
publication_container = container.findAll("dd",{"class":"data publication-date"})
Publication_date = publication_container[0].text
closing_container = container.findAll("dd",{"class":"data date-closing"})
Closing_date = closing_container[0].text
gsin_container = container.findAll("li",{"class":"first"})
Gsin = gsin_container[0].text
notice_container = container.findAll("dd",{"class":"data php"})
Notice_type = notice_container[0].text
entity_container = container.findAll("dd",{"class":"data procurement-entity"})
Entity = entity_container[0].text
print("Title: " Title)
print("Publication_date: " Publication_date)
print("Closing_date: " Closing_date)
print("Gsin: " Gsin)
print("Notice: " Notice_type)
print("Entity: " Entity)
f.write(Title "," Publication_date "," Closing_date "," Gsin "," Notice_type "," Entity "n")
f.close()
Пожалуйста, дайте мне знать, если вы хотели бы видеть дальше. Rest определяет контейнеры данных, которые можно найти в HTML-коде и распечатать в csv.Любая помощь / совет будут высоко оценены. Спасибо!
Фактические результаты :
Код генерирует CSV-файл только для первой страницы.
Код не записывается поверх того, что уже было отсканировано (изо дня в день), по крайней мере
Ожидаемые результаты :
Код сканирует следующие страницы и распознает, когда нет страниц для просмотра.
Файл CSV будет генерировать 10 строк csv на страницу. (И какое бы количество ни было на последней странице, поскольку число не всегда равно 10).
Код будет написан поверх того, что уже было очищено (для более продвинутой аналитики с использованием инструментов Excel с историческими данными)
Комментарии:
1. первое, что я замечаю, это
f = open(filename, "w")
. Когда вы используете modew
, он перезаписывается. Поскольку вы хотите добавить к существующим данным, вы хотели бы изменить это наa
. Во-вторых, вам нужно выполнить итерацию по страницам, а затем записать их. На данный момент не похоже, что вы переходите с одной страницы html на следующую. Хотелось бы, чтобы для этого был API, но, похоже, это будет грубая сила. Я поработаю над этим, чтобы помочь вам2. Спасибо, chitown88! Хотите, чтобы я опубликовал оставшуюся часть кода? (спецификация контейнеров, которые нужно найти и записать в csv)
3. о да. это было бы полезно
4. Сообщение обновлено. Смотрите выше. Спасибо!
5. Я пошел дальше и сделал это без этого, так что вы можете вернуться, если хотите, и изменить мой
Ответ №1:
Некоторые могут сказать, что использование pandas является излишеством, но лично мне удобно им пользоваться, и мне просто нравится использовать его для создания таблиц и записи в файл.
также, вероятно, существует более надежный способ перехода от страницы к странице, но я просто хотел донести это до вас, и вы сможете с этим работать.
На данный момент я просто жестко прописываю значение следующей страницы (и я просто произвольно выбрал максимум 20 страниц), поэтому он начинается со страницы 1, а затем проходит через 20 страниц (или останавливается, как только доходит до недопустимой страницы).
import pandas as pd
from bs4 import BeautifulSoup
import requests
import os
filename = "BuyandSell.csv"
# Initialize an empty 'results' dataframe
results = pd.DataFrame()
# Iterarte through the pages
for page in range(0,20):
url = 'https://buyandsell.gc.ca/procurement-data/search/site?page=' str(page) 'amp;f[0]=sm_facet_procurement_data:data_data_tender_noticeamp;f[1]=dds_facet_date_published:dds_facet_date_published_today'
page_html = requests.get(url).text
page_soup = BeautifulSoup(page_html, "html.parser")
containers = page_soup.findAll("div",{"class":"rc"})
# Get data from each container
if containers != []:
for each in containers:
title = each.find('h2').text.strip()
publication_date = each.find('dd', {'class':'data publication-date'}).text.strip()
closing_date = each.find('dd', {'class':'data date-closing'}).text.strip()
gsin = each.find('dd', {'class':'data gsin'}).text.strip()
notice_type = each.find('dd', {'class':'data php'}).text.strip()
procurement_entity = each.find('dd', {'data procurement-entity'}).text.strip()
# Create 1 row dataframe
temp_df = pd.DataFrame([[title, publication_date, closing_date, gsin, notice_type, procurement_entity]], columns = ['Title', 'Publication Date', 'Closing Date', 'GSIN', 'Notice Type', 'Procurement Entity'])
# Append that row to a 'results' dataframe
results = results.append(temp_df).reset_index(drop=True)
print ('Aquired page ' str(page 1))
else:
print ('No more pages')
break
# If already have a file saved
if os.path.isfile(filename):
# Read in previously saved file
df = pd.read_csv(filename)
# Append the newest results
df = df.append(results).reset_index()
# Drop and duplicates (incase the newest results aren't really new)
df = df.drop_duplicates()
# Save the previous file, with appended results
df.to_csv(filename, index=False)
else:
# If a previous file not already saved, save a new one
df = results.copy()
df.to_csv(filename, index=False)
Комментарии:
1. Chitown88, большое вам спасибо. Частично имеет смысл, поскольку я смотрю на это. Я постараюсь поработать с этим и вернусь, если у меня возникнут дополнительные вопросы. Действительно ценю вашу помощь! Спасибо!
2. прохладный. обязательно примите ответ, если он удовлетворил ваши потребности
3. Как мне это сделать? 🙂
4. треугольниками вверх и вниз (с большим 0) по моему решению. Должна быть галочка или что-то подобное, что позволяет вам принять ответ
5. Привет @chitown88 — Код работает идеально, спасибо за вашу помощь. Один дополнительный вопрос — Как бы мне добавить функцию, которая позволяет мне использовать учетные данные для автоматического входа на веб-сайты, требующие учетных данных? Должен ли я опубликовать это под новым вопросом? Пожалуйста, дайте мне знать.