Как извлечь веб-данные с помощью Python, BeautiflSoup и механизировать из таблицы - PullRequest
2 голосов
/ 16 августа 2011

Я хотел бы извлечь данные из таблицы на этом сайте: http://www.pgatour.com/r/stats/info/xm.html?101 А затем сохраните его как .csv и перенесите на лист iWorks Numbers. Я пытался с Python, BeautifulSoup и механизировать. Я пытался без знания, глядя на другие примеры, но безуспешно. Я зашел так далеко:

from BeautifulSoup import BeautifulSoup, SoupStrainer
from mechanize import Browser
import re
br = Browser()
response = br.open("http://www.pgatour.com/r/stats/info/xm.html?101").read()

Затем я смотрю на код с firebug и думаю, что мне нужно проанализировать данные, которые находятся между <tbody> и </tbody>. Но я не знаю, как это сделать. Любая помощь высоко ценится.

1 Ответ

4 голосов
/ 16 августа 2011

На главной странице статистика тура, кажется, заполняется JavaScript <div class="tourViewData"> ... populateDDs(); BS не разбирает Javascript, см. Много других SO вопросов по этому поводу. (Я не знаю, как решить эту часть. В худшем случае выберите и сохраните этот выбор HTML как локальный HTML-файл, как обходной путь.)

Во-первых, установите s как объект BeautifulSoup для этого URL (я использовал twill, а не rawize, поместите здесь свой аналог механизации):

from BeautifulSoup import BeautifulSoup, SoupStrainer
#from mechanize import Browser
from twill.commands import *
import re

go("http://www.pgatour.com/r/stats/info/xm.html?101")
s = BeautifulSoup(get_browser().get_html())

В любом случае таблица статистики, которую вы ищете, является таблицей, помеченной <tbody><tr class="tourStatTournHead">. Просто чтобы сделать вещи немного странными, атрибут tag в его строках поочередно определяется как <tr class="tourStatTournCellAlt" или <tr class="".... Мы должны искать первый <tr class="tourStatTournCellAlt", а затем обрабатывать каждый <tr> в таблице, кроме строк заголовка (<tr class="tourStatTournHead">).

Чтобы перебрать строки:

tbl = s.find('table', {'class':'tourStatTournTbl'})

def extract_text(ix,tg):
    if ix==2: # player name field, may be hierarchical
        tg = tg.findChildren()[0] if (len(tg.findChildren())>0) else tg
    return tg.text.encode()

for rec in tbl.findAll('tr'): # {'class':'tourStatTournCellAlt'}):
    # Skip header rows
    if (u'tourStatTournHead' in rec.attrs[0]):
        continue        
    # Extract all fields
    (rank_tw,rank_lw,player,rounds,avg,tot_dist,tot_drives) = \
        [extract_text(i,t) for (i,t) in enumerate(rec.findChildren(recursive=False))]
    # ... do stuff

Мы добавили вспомогательную функцию для имени игрока (она может быть или не быть иерархической, если в нее встроен логотип Titleist.) Вероятно, вы хотите преобразовать большинство полей в int (), кроме player (string) и avg (float); если это так, не забудьте убрать необязательный 'T' (для связанного) из полей ранга и убрать запятую из tot_dist.

...