Итак, я стремлюсь очистить 2 таблицы (в разных форматах) с веб-сайта - Публичный поиск FSC после повторения этого по списку кодов лицензий. Моя проблема в том, что, поскольку две таблицы, которые мне нужны, данные о продукте и данные сертификата, находятся в двух разных форматах, мне приходится очищать их отдельно. Например, данные о продукте представлены на веб-странице в обычном формате "tr", а данные сертификата - в форме "div".
Из предыдущего вопроса, который я задал, я почти решил свою проблему, и я могу полностью получить данные сертификата (форма «div») для ряда лицензионных кодов. Однако я не могу вывести таблицу данных о продукте так, как мне хотелось бы. Вместо того, чтобы показывать данные о продукте для 5 лицензионных кодов, он показывает мне 5 копий первого лицензионного кода. Я пробовал поместить этот парсинг в определенную функцию get_data_by_code, но мне все равно не удалось получить его в желаемом формате, который представляет собой просто таблицу в файле CSV.
В принципе, я не уверен, где включить эту очистку в мою функцию / скрипт, поэтому любой ввод будет очень признателен, спасибо.
df3 = pd.DataFrame()
df = pd.read_csv("MS_License_Codes.csv")
codes = df["License Code"]
data = [
('code', code),
('submit', 'Search'),
]
response = requests.post('https://info.fsc.org/certificate.php', data=data)
soup = BeautifulSoup(response.content, 'lxml')
def get_data_by_code(code):
data = [
('code', code),
('submit', 'Search'),
]
response = requests.post('https://info.fsc.org/certificate.php', data=data)
soup = BeautifulSoup(response.content, 'lxml')
#scraping the certificate data
status = soup.find_all("label", string = "Status")[0].find_next_sibling('div').text
first_issue_date = soup.find_all("label", string = "First Issue Date")[0].find_next_sibling('div').text
last_issue_date = soup.find_all("label", string = "Last Issue Date")[0].find_next_sibling('div').text
expiry_date = soup.find_all("label", string = "Expiry Date")[0].find_next_sibling('div').text
standard = soup.find_all("label", string = "Standard")[0].find_next_sibling('div').text
return [code, status, first_issue_date, last_issue_date, expiry_date, standard]
# Just insert here output filename and codes to parse...
OUTPUT_FILE_NAME = 'Certificate_Data.csv'
df3 = pd.DataFrame()
with open(OUTPUT_FILE_NAME, 'w') as f:
writer = csv.writer(f)
for code in codes:
print('Getting code# {}'.format(code))
writer.writerow((get_data_by_code(code)))
##attempting to scrape the product data
table = soup.find_all('table')[0]
df1, = pd.read_html(str(table))
df3 = df3.append(df1)
df3.to_csv('Product_Data.csv', index = False, encoding='utf-8')
РЕДАКТИРОВАТЬ
Итак, используя приведенный ниже код, я получаю 5 копий данных о продукте последнего лицензионного кода ... немного ближе, но я все еще не понимаю, почему это так.
df3 = pd.DataFrame()
for code in codes:
print('Getting code# {}'.format(code))
response = requests.post('https://info.fsc.org/certificate.php', data=data)
soup = BeautifulSoup(response.content, 'lxml')
table = soup.find_all('table')[0]
df1, = pd.read_html(str(table))
df3 = df3.append(df1)
df3.to_csv('Product_Data.csv', index = False, encoding='utf-8')
РЕДАКТИРОВАТЬ 2
Примеры кодов, которые я использовал:
codes = ['FSC-C001777', 'FSC-C124838' ,'FSC-C068163','FSC-C101537','FSC-C005776']
Формат Редактировать
Это правильный табличный формат, однако, как вы можете видеть, это информация из первого лицензионного кода, повторяемая 5 раз, в отличие от уникальных данных.
Это формат и информация, которые мне нужны, здесь все работает нормально:

Каков ваш ожидаемый результат для введенных вами кодов? Не могли бы вы добавить, как должен выглядеть файл CSV (в текстовом формате)?
@MartinEvans Я не был уверен, что вы имели в виду под текстовым форматом, поэтому я добавил скриншоты моих текущих результатов, так как они находятся в правильном формате, только один из них содержит неправильную информацию.
Спасибо. Необработанный текст предпочтительнее снимков экрана.






Для предоставленного вами codes этого упрощенного подхода должно быть достаточно. Он просто извлекает необходимую информацию прямо из BeautifulSoup без необходимости использовать Pandas для ее извлечения:
from bs4 import BeautifulSoup
import requests
import csv
fieldnames_cert = ['Code', 'Status', 'First Issue Date', 'Last Issue Date', 'Expiry Date', 'Standard']
fieldnames_prod = ['Code', 'Product Type', 'Trade Name', 'Species', 'Primary Activity', 'Secondary Activity', 'Main Output Category']
codes = ['FSC-C001777', 'FSC-C124838', 'FSC-C068163', 'FSC-C101537', 'FSC-C005776']
with open('Certificate_Data.csv', 'wb') as f_output_cert, \
open('Product_Data.csv', 'wb') as f_output_prod:
csv_output_cert = csv.writer(f_output_cert)
csv_output_cert.writerow(fieldnames_cert)
csv_output_prod = csv.writer(f_output_prod)
csv_output_prod.writerow(fieldnames_prod)
for code in codes:
print('Getting code# {}'.format(code))
response = requests.post('https://info.fsc.org/certificate.php', data = {'code' : code, 'submit' : 'Search'})
soup = BeautifulSoup(response.content, 'lxml')
# Extract the certificate data
div_cert = soup.find('div', class_='certificatecl')
csv_output_cert.writerow([code] + [div.text for div in div_cert.find_all('div')])
# Extract the product data
table = soup.find('h2', id='products').find_next_sibling('table')
for tr in table.find_all('tr')[1:]:
row = [td.get_text(strip=True).encode('utf-8') for td in tr.find_all('td')]
csv_output_prod.writerow([code] + row)
В результате будет получен Certificate_Data.csv, содержащий:
Code,Status,First Issue Date,Last Issue Date,Expiry Date,Standard
FSC-C001777,Valid,2009-04-01,2018-02-16,2019-04-01,FSC-STD-40-004 V3-0
FSC-C124838,Valid,2015-03-23,2015-03-23,2020-03-22,FSC-STD-40-004 V3-0
FSC-C068163,Valid,2010-03-01,2017-08-23,2022-08-22,FSC-STD-40-003 V2-1;FSC-STD-40-004 V3-0
FSC-C101537,Valid,2010-10-01,2013-11-28,2018-11-27,FSC-STD-40-003 V2-1;FSC-STD-40-004 V3-0
FSC-C005776,Valid,2007-07-17,2017-07-17,2022-07-16,FSC-STD-40-004 V3-0
И произвести Product_Data.csv, содержащий:
Code,Product Type,Trade Name,Species,Primary Activity,Secondary Activity,Main Output Category
FSC-C001777,W12 Indoor furnitureW12.4 Beds,,,Secondary Processor,Secondary Processor,FSC Mix
FSC-C124838,"W18 Other manufactured wood productsW18.4 Tools, tool bodies and handles",, Abies spp; Betula spp.; Fagus sylvatica L.; Hevea brasiliensis; Paulownia tomentosa (Thunb. ex Murr) Steud; Picea spp.; Populus spp.; Quercus spp; Schima wallichii (DC.) Korth.; Swietenia macrophylla; Tilia spp.; Ulmus spp.,brokers/traders with physical posession,,FSC Mix;FSC 100%;FSC Recycled
FSC-C068163,P2 Paper,,,brokers/traders with physical posession,Distributor/Wholesaler,FSC Mix;FSC 100%;FSC Recycled
FSC-C068163,P3 Paperboard,,,brokers/traders with physical posession,Distributor/Wholesaler,FSC Mix;FSC 100%;FSC Recycled
FSC-C101537,P8 Printed materials,,,Printing and related service,Secondary Processor,FSC Mix;FSC 100%;FSC Recycled
FSC-C101537,P7 Stationery of paper,,,Printing and related service,Secondary Processor,FSC Mix;FSC 100%;FSC Recycled
FSC-C005776,W12 Indoor furnitureW12.10 Cupboards and chests,"Outros produtos, (baú, quadro espelho, etc.)", Eucalyptus spp; Pinus spp.,Secondary Processor,,FSC Mix
FSC-C005776,W12 Indoor furnitureW12.7 Office furniture,"Produtos para escritório (escrivaninha, mesa, gaveteiros, etc.)", Eucalyptus spp; Pinus elliottii,Secondary Processor,,FSC Mix
FSC-C005776,W12 Indoor furnitureW12.12 Parts of furniture,"Partes de movéis, (peças de reposição)", Eucalyptus spp; Pinus taeda,Secondary Processor,,FSC Mix
FSC-C005776,W12 Indoor furnitureW12.4 Beds,Camas, Eucalyptus spp; Pinus taeda,Secondary Processor,,FSC Mix
Спасибо за помощь, Мартин! Однако я думаю, что, возможно, плохо объяснил свою проблему. Таблица, которую вы обрисовали выше в своем ответе, я уже успешно извлек. Это другая таблица (см. Мое изображение «данные о продукте» в редактировании), в текстовых полях которой есть такие данные, как мебель для дома, кровати и т. д. Эту таблицу я не могу правильно извлечь при циклическом просмотре кодов лицензий.
К сожалению, не заметил, что вы создаете два вывода на страницу. Pandas read_html() иногда может быть действительно полезен, но когда он терпит неудачу, лучше использовать собственный код для извлечения нужной информации.
Это потрясающе, спасибо вам огромное !! Я ненавижу вас беспокоить, но все работает отлично до последнего лицензионного кода (по крайней мере, для меня, может быть, потому что у меня python 2.7), но я получаю эту ошибку: кодек ascii не может кодировать символ u '\ xfa' в позиции 20 : порядковый номер вне диапазона (128). Я попытался добавить .encode ('utf-8'). Strip () после строки, но это привело к ошибке. Есть ли другой способ решить эту проблему?
Вы можете добавить его в понимание списка. Также, если вы используете Python 2.x, вам необходимо изменить использование 'wb' в качестве режима записи. Я обновил скрипт.
Я сам решил проблему с помощью sys.setdefaultencoding ('utf8')! Еще раз большое спасибо за вашу помощь и отзывы, это очень помогло.
@MartinEvans Я добавил несколько ниже, в РЕДАКТИРОВАТЬ 2.