Очистка таблицы с веб-страницы в формате <div>- с использованием Beautiful Soup - PullRequest
0 голосов
/ 06 июля 2018

Итак, я собираюсь очистить 2 таблицы (в разных форматах) с веб-сайта - https://info.fsc.org/details.php?id=a0240000005sQjGAAU&type=certificate после использования панели поиска для повторения этого по списку кодов лицензий. Я еще не включил цикл полностью, но я добавил его сверху для полноты.

Моя проблема заключается в том, что поскольку две таблицы, которые я хочу, - Данные о продукте и Данные сертификата - имеют два разных формата, поэтому мне приходится обрабатывать их отдельно. Поскольку данные о продукте представлены в обычном формате «tr» на веб-странице, этот бит прост, и мне удалось извлечь из него CSV-файл. Сложнее всего извлечь данные сертификата, так как они находятся в форме "div".

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

#namelist = open('example.csv', newline='', delimiter = 'example')
#for name in namelist:
    #include all of the below

driver = webdriver.Chrome(executable_path="/Users/jamesozden/Downloads/chromedriver")
url = "https://info.fsc.org/certificate.php"
driver.get(url)

search_bar = driver.find_element_by_xpath('//*[@id="code"]')
search_bar.send_keys("FSC-C001777")
search_bar.send_keys(Keys.RETURN)
new_url = driver.current_url

r = requests.get(new_url)
soup = BeautifulSoup(r.content,'lxml')
table = soup.find_all('table')[0] 
df, = pd.read_html(str(table))
certificate = soup.find(class_= 'certificatecl').text
##certificate1 = pd.read_html(str(certificate))

driver.quit()

df.to_csv("Product_Data.csv", index=False)
##certificate1.to_csv("Certificate_Data.csv", index=False)

#print(df[0].to_json(orient='records'))
print certificate

Выход:

Status
Valid
First Issue Date
2009-04-01
Last Issue Date
2018-02-16
Expiry Date
2019-04-01
Standard
FSC-STD-40-004 V3-0

Что я хочу, но более сотни / тысячи кодов лицензий (я только что вручную создал этот пример в Excel):

Желаемый выход

EDIT

Итак, пока это работает для данных сертификата, я также хочу собрать данные продукта и вывести их в другой файл .csv. Однако в настоящее время печатается только 5 копий данных продукта для окончательного лицензионного кода, а это не то, что мне нужно.

Новый код:

df = pd.read_csv("MS_License_Codes.csv")
codes = df["License Code"]

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')

    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'
#codes = ['C001777', 'C001777', 'C001777', 'C001777']


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)))
        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 ]

0 голосов
/ 11 июля 2018

хорошо ... вы должны оттачивать свои навыки (:

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)))
        ### HERE'S THE PROBLEM:
        # "soup" variable is declared inside of "get_data_by_code" function.
        # So you can't use it in outer context.
        table = soup.find_all('table')[0] # <--- you should move this line to 
        #definition of "get_data_by_code" function and return it's value somehow...
        df1, = pd.read_html(str(table))
        df3 = df3.append(df1) 

df3.to_csv('Product_Data.csv', index = False, encoding='utf-8')

В соответствии с примером вы можете вернуть словарь значений из функции "get_data_by_code":

 def get_data_by_code(code):
 ...
     table = soup.find_all('table')[0]
     return dict(row=row, table=table)
0 голосов
/ 06 июля 2018

Вот все, что вам нужно. Нет хромедрайвера. Нет панд. Забудьте об этом в контексте очистки.

import requests
import csv
from bs4 import BeautifulSoup

# This is all what you need for your task. Really.
# No chromedriver. Don't use it for scraping. EVER.
# No pandas. Don't use it for writing csv. It's not what pandas was made for.

#Function to parse single data page based on single input code.
def get_data_by_code(code):

    # Parameters to build POST-request. 
    # "type" and "submit" params are static. "code" is your desired code to scrape.
    data = [
        ('type', 'certificate'),
        ('code', code),
        ('submit', 'Search'),
    ]

    # POST-request to gain page data.
    response = requests.post('https://info.fsc.org/certificate.php', data=data)
    # "soup" object to parse html data.
    soup = BeautifulSoup(response.content, 'lxml')

    # "status" variable. Contains first's found [LABEL tag, with text="Status"] following sibling DIV text. Which is status.
    status = soup.find_all("label", string="Status")[0].find_next_sibling('div').text
    # Same for issue dates... etc.
    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

    # Returning found data as list of values.
    return [response.url, status, first_issue_date, last_issue_date, expiry_date, standard]

# Just insert here output filename and codes to parse...
OUTPUT_FILE_NAME = 'output.csv'
codes = ['C001777', 'C001777', 'C001777', 'C001777']

with open(OUTPUT_FILE_NAME, 'w') as f:
    writer = csv.writer(f)
    for code in codes:
        print('Getting code# {}'.format(code))

        #Writing list of values to file as single row.
        writer.writerow((get_data_by_code(code)))

Здесь все действительно просто. Я бы посоветовал вам потратить некоторое время на вкладке «Сеть» инструментов разработчика Chrome, чтобы лучше понять подделку запросов, которая необходима для очистки задач.

enter image description here

Как правило, вам не нужно запускать chrome, чтобы нажать кнопку «поиск», вам нужно подделать запрос, сгенерированный этим щелчком. То же самое для любой формы и AJAX.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...