Стол выскабливает с Beautifulsoup4 отсутствующими клетками - PullRequest
0 голосов
/ 09 февраля 2019

Я столкнулся с каким-то странным поведением с BS4.Я продублировал 20 страниц сайта, который я буду просматривать, и этот код прекрасно работает на моем частном веб-сервере.Когда я использую его на реальном сайте, он случайно пропускает 8-й столбец строки.Я не сталкивался с этим раньше, и я, кажется, не могу найти другие сообщения с этой проблемой.Восьмой столбец - "частота_ранков".Что происходит, что это происходит только в последнем столбце и как мне это исправить?

import requests
import json
from bs4 import BeautifulSoup

base_url = 'http://hanzidb.org'


def soup_the_page(page_number):
    url = base_url + '/character-list/by-frequency?page=' + str(page_number)    
    response = requests.get(url, timeout=5)
    soup = BeautifulSoup(response.content, 'html.parser')
    return soup


def get_max_page(soup):
    paging = soup.find_all("p", {'class': 'rigi'})
    # Isolate the first paging link
    paging_link = paging[0].find_all('a')
    # Extract the last page number of the series
    max_page_num = int([item.get('href').split('=')[-1] for item in paging_link][-1])
    return max_page_num


def crawl_hanzidb():
    result = {}

    # Get the page scrape data
    page_content = soup_the_page(1)
    # Get the page number of the last page
    last_page = get_max_page(page_content)
    # Get the table data
    for p in range(1, last_page + 1):
        page_content = soup_the_page(p)
        for trow in page_content.find_all('tr')[1:]:
            char_dict = {}
            i = 0
            # Set the character as the dict key
            character = trow.contents[0].text
            # Initialize list on dict key
            result[character] = []
            # Return list of strings from trow.children to parse urls
            for tcell in trow.children:
                char_position = 0
                radical_position = 3
                if i == char_position or i == radical_position:
                    for content in tcell.children:
                        if type(content).__name__ == 'Tag':
                            if 'href' in content.attrs:
                                url = base_url + content.attrs.get('href')
                                if i == char_position:
                                    char_dict['char_url'] = url
                                if i == radical_position:
                                    char_dict['radical_url'] = url
                i += 1
            char_dict['radical'] = trow.contents[3].text[:1]
            char_dict['pinyin'] = trow.contents[1].text
            char_dict['definition'] = trow.contents[2].text
            char_dict['hsk_level'] = trow.contents[5].text[:1] if trow.contents[5].text[:1].isdigit() else ''
            char_dict['frequency_rank'] = trow.contents[7].text if trow.contents[7].text.isdigit() else ''
            result[character].append(char_dict)
        print('Progress: ' + str(p) + '%.')
    return(result)


crawl_data = crawl_hanzidb()
with open('hanzidb.json', 'w') as f:
    json.dump(crawl_data, f, indent=2, ensure_ascii=False)

1 Ответ

0 голосов
/ 09 февраля 2019

Кажется, проблема в том, что сайт имеет некорректный HTML.Если вы посмотрите на источник сайта, который вы разместили, перед столбцом рейтинга частоты есть два закрывающих тега </td>.Пример:

<tr>
    <td><a href="/character/的">的</a></td>
    <td>de</td><td><span class="smmr">possessive, adjectival suffix</span></td>
    <td><a href="/character/白" title="Kangxi radical 106">白</a>&nbsp;106.3</td>
    <td>8</td><td>1</td>
    <td>1155</td></td>
    <td>1</td>
 </tr>

Я думаю, что это вызывает проблемы с анализатором, который вы используете (html.parser).Если вы устанавливаете парсер lxml, он, кажется, работает.

Попробуйте:

Сначала , установите парсер lxml ...

pip install lxml

Затем , измените анализатор в вашем soup_the_page() методе:

soup = BeautifulSoup(response.content, 'lxml')

Затем запустите ваш скрипт.Вроде работает.print(trow.contents[7].text) больше не выдает ошибку индекса вне диапазона.

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