Java:У меня есть большая строка html, и мне нужно извлечь текст href =“...”

StackOverflow https://stackoverflow.com/questions/1670593

  •  13-09-2019
  •  | 
  •  

Вопрос

У меня есть эта строка, содержащая большой фрагмент html, и я пытаюсь извлечь ссылку из части строки href="...".Ссылка href может быть в одной из следующих форм:

<a href="..." />
<a class="..." href="..." />

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

        String innerHTML = getHTML(); 
  Pattern p = Pattern.compile("href=\"(.*)\"", Pattern.DOTALL);
  Matcher m = p.matcher(innerHTML);
  if (m.find()) {
   // Get all groups for this match
   for (int i=0; i<=m.groupCount(); i++) {
    String groupStr = m.group(i);
    System.out.println(groupStr);

   }
  }

Кто-нибудь может сказать мне, что не так с моим кодом?Я сделал это на php, но в Java я почему-то делаю что-то не так...Что происходит, так это то, что он печатает всю html-строку целиком всякий раз, когда я пытаюсь ее распечатать...

Редактировать:Просто для того, чтобы все знали, с какой строкой я имею дело:

<a class="Wrap" href="item.php?id=43241"><input type="button">
    <span class="chevron"></span>
  </a>
  <div class="menu"></div>

Каждый раз, когда я запускаю код, он печатает всю строку целиком...В этом-то и проблема...

И об использовании JTidy...Я занимаюсь этим, но было бы интересно узнать, что пошло не так и в этом случае...

Это было полезно?

Решение

.* 

Это жадная операция, которая принимает любой символ, включая кавычки.

Попробуйте что-то вроде:

"href=\"([^\"]*)\""

Другие советы

С опубликованным вами кодом есть две проблемы:

Во-первых .* в вашем регулярном выражении является жадным.Это приведет к тому, что он будет соответствовать всем символам до последнего. " персонаж, которого можно найти.Вы можете сделать это совпадение нежадным, изменив его на .*?.

Во-вторых, чтобы подобрать все совпадения, вам нужно продолжать итерацию с помощью Matcher.find вместо того, чтобы искать группы.Группы предоставляют вам доступ к каждому разделу регулярного выражения, заключенному в круглые скобки.Однако вы ищете каждый раз, когда все регулярное выражение совпадает.

Объединив все это, вы получите следующий код, который должен делать то, что вам нужно:

Pattern p = Pattern.compile("href=\"(.*?)\"", Pattern.DOTALL);
Matcher m = p.matcher(innerHTML);

while (m.find()) 
{
    System.out.println(m.group(1));
}

Regex — отличный инструмент, но он не подходит для этой конкретной цели.Обычно для этого вы хотите использовать парсер на основе стека.Взгляните на API-интерфейс синтаксического анализатора Java HTML, например jTidy.

Используйте встроенный синтаксический анализатор.Что -то вроде:

    EditorKit kit = new HTMLEditorKit();
    HTMLDocument doc = (HTMLDocument)kit.createDefaultDocument();
    doc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
    kit.read(reader, doc, 0);

    HTMLDocument.Iterator it = doc.getIterator(HTML.Tag.A);

    while (it.isValid())
    {
        SimpleAttributeSet s = (SimpleAttributeSet)it.getAttributes();
        String href = (String)s.getAttribute(HTML.Attribute.HREF);
        System.out.println( href );
        it.next();
    }

Или используйте Parserc обратный вызов:

import java.io.*;
import java.net.*;
import javax.swing.text.*;
import javax.swing.text.html.parser.*;
import javax.swing.text.html.*;

public class ParserCallbackText extends HTMLEditorKit.ParserCallback
{
    public void handleStartTag(HTML.Tag tag, MutableAttributeSet a, int pos)
    {
        if (tag.equals(HTML.Tag.A))
        {
            String href = (String)a.getAttribute(HTML.Attribute.HREF);
            System.out.println(href);
        }
    }

    public static void main(String[] args)
        throws Exception
    {
        Reader reader = getReader(args[0]);
        ParserCallbackText parser = new ParserCallbackText();
        new ParserDelegator().parse(reader, parser, true);
    }

    static Reader getReader(String uri)
        throws IOException
    {
        // Retrieve from Internet.
        if (uri.startsWith("http:"))
        {
            URLConnection conn = new URL(uri).openConnection();
            return new InputStreamReader(conn.getInputStream());
        }
        // Retrieve from file.
        else
        {
            return new FileReader(uri);
        }
    }
}

Читателем может быть StringReader.

Еще один простой и надежный способ сделать это — использовать Джсуп

Document doc = Jsoup.connect("http://example.com/").get();
Elements links = doc.select("a[href]");
for (Element link : links){
  System.out.println(link.attr("abs:href"));
}

вы можете использовать библиотеку парсера HTML. аккуратный например, дает вам DOM-модель html, из которой вы можете извлечь все элементы «a» и прочитать их атрибут «href».

"href=\"(.*?)\"" тоже должно работать, но думаю, ответ Кугеля сработает быстрее.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top