BeautifulSoup4 scrapping: при экспорте данных в csv у панд "все массивы должны быть одинаковой длины" - PullRequest
0 голосов
/ 29 августа 2018

Я использую BeautifulSoup4 для очистки информации с веб-сайта и Pandas для экспорта данных в CSV-файл. В словаре 5 столбцов данных, представленных 5 списками. Однако, поскольку на сайте нет полных данных для всех 5 категорий, в некоторых списках меньше элементов, чем в других. Поэтому, когда я пытаюсь экспортировать данные, панды дают мне

ValueError: все массивы должны быть одинаковой длины.

Как лучше всего справиться с этой ситуацией? Чтобы быть точным, списки с меньшим количеством пунктов являются «авторами» и «страницами». Заранее спасибо!
Код:

import requests as r
from bs4 import BeautifulSoup as soup
import pandas 

#make a list of all web pages' urls
webpages=[]
for i in range(15):
    root_url = 'https://cross-currents.berkeley.edu/archives?author=&title=&type=All&issue=All&region=All&page='+ str(i)
    webpages.append(root_url)
print(webpages)
#start looping through all pages
titles = []
journals = []
authors = []
pages = []
dates = []
issues = []

for item in webpages:
    headers = {'User-Agent': 'Mozilla/5.0'}
    data = r.get(item, headers=headers)
    page_soup = soup(data.text, 'html.parser')

    #find targeted info and put them into a list to be exported to a csv file via pandas
    title_list = [title.text for title in page_soup.find_all('div', {'class':'field field-name-node-title'})]
    titles += [el.replace('\n', '') for el in title_list]

    journal_list = [journal.text for journal in page_soup.find_all('em')]
    journals += [el.replace('\n', '') for el in journal_list] 

    author_list = [author.text for author in page_soup.find_all('div', {'class':'field field--name-field-citation-authors field--type-string field--label-hidden field__item'})]
    authors += [el.replace('\n', '') for el in author_list]

    pages_list = [pages.text for pages in page_soup.find_all('div', {'class':'field field--name-field-citation-pages field--type-string field--label-hidden field__item'})]
    pages += [el.replace('\n', '') for el in pages_list]

    date_list = [date.text for date in page_soup.find_all('div', {'class':'field field--name-field-date field--type-datetime field--label-hidden field__item'})]
    dates += [el.replace('\n', '') for el in date_list]

    issue_list = [issue.text for issue in page_soup.find_all('div', {'class':'field field--name-field-issue-number field--type-integer field--label-hidden field__item'})]
    issues += [el.replace('\n', '') for el in issue_list]

# export to csv file via pandas
dataset = {'Title': titles, 'Author': authors, 'Journal': journals, 'Date': dates, 'Issue': issues, 'Pages': pages}
df = pandas.DataFrame(dataset)
df.index.name = 'ArticleID'
df.to_csv('example45.csv', encoding="utf-8")

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Вы можете создать фрейм данных только из первого списка (df = pandas.DataFrame({'Title': titles})), а затем добавить остальные:

dataset = {'Author': authors, 'Journal': journals, 'Date': dates, 'Issue': issues, 'Pages': pages}
df2 = pandas.DataFrame(dataset) 
df_final = pandas.concat([df, df2], axis=1)

Это даст вам пробелы (или NaN), где у вас отсутствуют данные.

Проблема с этим, как и с ответом @ WurzelseppQX, заключается в том, что данные могут не совпадать, что делает их довольно бесполезными. Поэтому, возможно, лучше всего изменить свой код таким образом, чтобы вы всегда добавляли что-то в каждый список для каждого запуска цикла, просто делая его равным 0 или blank, если там ничего нет.

0 голосов
/ 29 августа 2018

Если вы уверены, что для примеров длина заголовков всегда правильна, вы можете сделать что-то подобное:

title_list = [title.text for title in page_soup.find_all('div', {'class':'field field-name-node-title'})]
titles_to_add = [el.replace('\n', '') for el in title_list]
titles += titles_to_add

...

author_list = [author.text for author in page_soup.find_all('div', {'class':'field field--name-field-citation-authors field--type-string field--label-hidden field__item'})]
authors_to_add = [el.replace('\n', '') for el in author_list]
if len(authors_to_add) < len(titles_to_add):
    while len(authors_to_add) < len(titles_to_add):
        authors_to_add += " "    
authors += authors_to_add

pages_list = [pages.text for pages in page_soup.find_all('div', {'class':'field field--name-field-citation-pages field--type-string field--label-hidden field__item'})]
pages_to_add = [el.replace('\n', '') for el in pages_list]
if len(pages_to_add) < len(titles_to_add):
    while len(pages_to_add) < len(titles_to_add):
        pages_to_add += " "
pages += pages_to_add

Однако ... Это просто добавит элементы в столбцы, чтобы они имели правильную длину, чтобы вы могли создать фрейм данных. Но в вашем фрейме данных авторы и страницы не будут в правильном ряду. Вам придется немного изменить свой алгоритм, чтобы достичь конечной цели ... Было бы лучше, если бы вы перебирали все строки на своей странице и получали заголовок и т. Д., Например:

rows = page_soup.find_all('div', {'class':'views-row'})
    for row in rows:
        title_list = [title.text for title in row.find_all('div', {'class':'field field-name-node-title'})]
...

Затем вам нужно проверить, существует ли заголовок, автор и т. Д. ... 1007 * и, если нет, добавить "None" или что-то еще в определенный список. Тогда все должно быть правильно в вашем df.

...