Извлечение строк таблицы с определенным элементом из HTML, используя HTML :: TableExtract в perl - PullRequest
0 голосов
/ 30 июля 2011

Я усвоил сложный способ, которым регулярные выражения не могут адекватно анализировать html, прежде чем находить пост за постом об этом.

Я пытаюсь извлечь непрочитанные сообщения с веб-страницы, которая находится в таблице. Это единственная таблица на запрашиваемой странице, так что эта часть хороша. Каждая строка представляет собой набор столбцов, касающихся PM. Класс TR информирует о непрочитанном / прочитанном PM. - это то, что меня ловит.

Я пытался использовать HTML :: TableExtract, который почти работал отлично, за исключением того, что я не могу понять, как проверить элемент TR.

Пример структуры таблицы:

<table>
    <tr class="header">
        <td></td>
        <td>Subject</td>
        <td>Sender</td>
        <td>Date</td>
    </tr>
    <tr class="unread">
        <td>checkbox for multi-edit stuff</td>
        <td>Example of an unread PM</td>
        <td>Me</td>
        <td>Jul 30, 2011</td>
    </tr>
    <tr class="read">
        ....   
    </tr>
</table>

Использование HTML :: TableExtract Я смог получить все, кроме классов непрочитанных / прочитанных. Вот так:

$t = HTML::TableExtract->new(keep_html);
$t->parse($lwp_data);
foreach $t2 ($t->tables) {
    foreach $row ($t2->rows) {
#Can't find a way to search for <tr class="unread". As
#Attribute data is stripped at this point by HTML::TableExtract

        #This now shows EVERY PM in the list
        print join(',', @$row), "\n";
    }
 }

Как еще я могу разобрать это и получить только TR с class = "unread"?

Поиски привели к слишком сложным ответам или ответам, которые не вполне решают мою проблему.

Вот самый последний метод, который я использую, чтобы получить то, что я хочу (И он работает, мне просто интересно, как это сделать лучше):

 while ($page =~ m/(unreadpm.*?\/tr)/sg) {
      $data = $1;
      if ($data =~ m(value="(\d+)".*?<a href="(inbox.php\?action=viewconv&amp;id=\d+)">(.*?)</a>\n</strong>\s+</td>\n\s+<td>(.*?)</td>)sg) {
           my ($id,$link,$subject,$user) = ($1, $2, $3, $4);
           if ($user =~ m(user\.php\?id=\d+">(.*?)</a>)) {
                $user = $1;
           }

           if (grep $_ eq $id, @ids) {
                print "Message ID: $id already listed\n"
           } else {
                print "Emailing - Subject: $subject by $user. ID: $id Link: $link ...";
                send_email($subject,$user,$link);
                print "done.\n";
                push @ids, $id;
           }
      }
 }

Ответы [ 2 ]

1 голос
/ 30 июля 2011

Я могу рекомендовать HTML :: TreeBuilder в сочетании с XML :: LibXML для выполнения работы.

my $tree = HTML::TreeBuilder->new_from_content( $html );
my $xml  = $tree->as_XML;
my $doc = XML::LibXML->load_xml(string => $xml);

Затем вы можете использовать findvalue , чтобы найти <tr> узлов, используя выражения XPath.

Используя HTML :: Selector :: XPath , вы даже можете использовать CSS-селекторы, чтобы добраться до <tr>.

0 голосов
/ 30 июля 2011

Если бы я понял вопрос, я бы сделал что-то вроде:

@html_lines = (use curl or otherwise to retrieve the html)

$GET_LINE = 0;

foreach $line (@html_lines)
{
  if ($line =~ /\<tr class="unread"\>/)
  {
      $GET_LINE = 1;
      next;
  }

  if ( ($line =~ |\</tr\>|) && ($GET_LINE) ) 
  { 
      $GET_LINE = 0;
      next;
  }

  if ($GET_LINE)
  {
     #process the <td> lines
  }
}

Примечание: я не гарантирую, что синтаксис правильный, но вы получите картину ...

...