Очистите 2 таблицы разных форматов с веб-страницы - Beautiful Soup

Итак, я стремлюсь очистить 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 раз, в отличие от уникальных данных.

Очистите 2 таблицы разных форматов с веб-страницы - Beautiful Soup

Это формат и информация, которые мне нужны, здесь все работает нормально: Очистите 2 таблицы разных форматов с веб-страницы - Beautiful Soup

@MartinEvans Я добавил несколько ниже, в РЕДАКТИРОВАТЬ 2.

Ozdanny 11.07.2018 15:58

Каков ваш ожидаемый результат для введенных вами кодов? Не могли бы вы добавить, как должен выглядеть файл CSV (в текстовом формате)?

Martin Evans 11.07.2018 16:45

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

Ozdanny 11.07.2018 17:00

Спасибо. Необработанный текст предпочтительнее снимков экрана.

Martin Evans 11.07.2018 17:02
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
499
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для предоставленного вами 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

Спасибо за помощь, Мартин! Однако я думаю, что, возможно, плохо объяснил свою проблему. Таблица, которую вы обрисовали выше в своем ответе, я уже успешно извлек. Это другая таблица (см. Мое изображение «данные о продукте» в редактировании), в текстовых полях которой есть такие данные, как мебель для дома, кровати и т. д. Эту таблицу я не могу правильно извлечь при циклическом просмотре кодов лицензий.

Ozdanny 11.07.2018 17:24

К сожалению, не заметил, что вы создаете два вывода на страницу. Pandas read_html() иногда может быть действительно полезен, но когда он терпит неудачу, лучше использовать собственный код для извлечения нужной информации.

Martin Evans 11.07.2018 17:54

Это потрясающе, спасибо вам огромное !! Я ненавижу вас беспокоить, но все работает отлично до последнего лицензионного кода (по крайней мере, для меня, может быть, потому что у меня python 2.7), но я получаю эту ошибку: кодек ascii не может кодировать символ u '\ xfa' в позиции 20 : порядковый номер вне диапазона (128). Я попытался добавить .encode ('utf-8'). Strip () после строки, но это привело к ошибке. Есть ли другой способ решить эту проблему?

Ozdanny 11.07.2018 18:13

Вы можете добавить его в понимание списка. Также, если вы используете Python 2.x, вам необходимо изменить использование 'wb' в качестве режима записи. Я обновил скрипт.

Martin Evans 11.07.2018 18:18

Я сам решил проблему с помощью sys.setdefaultencoding ('utf8')! Еще раз большое спасибо за вашу помощь и отзывы, это очень помогло.

Ozdanny 11.07.2018 18:20

Другие вопросы по теме