如何在网站上递归查找所有URL - java

时间:2018-03-23 21:57:55

标签: java url recursion

我有一个方法,允许我从页面获取所有URL(和可选 - 检查它是否有效)。 但它只适用于1页,我想查看所有的网站。需要进行递归。

private static FirefoxDriver driver;
public static void main(String[] args) throws Exception {
    driver = new FirefoxDriver();
    driver.get("https://example.com/");

    List<WebElement> allURLs = findAllLinks(driver);
    report(allURLs);

    // here are my trials for recursion
    for (WebElement element : allURLs) {
        driver.get(element.getAttribute("href"));
        List<WebElement> allUrls = findAllLinks(driver);
        report(allUrls);
    }
}
public static List findAllLinks(WebDriver driver)
{
    List<WebElement> elementList = driver.findElements(By.tagName("a"));
    elementList.addAll(driver.findElements(By.tagName("img")));
    List finalList = new ArrayList();
    for (WebElement element : elementList)
    {
        if(element.getAttribute("href") != null)
        {
            finalList.add(element);
        }
    }
    return finalList;
}
public static void report(List<WebElement> allURLs) {
    for(WebElement element : allURLs){
        System.out.println("URL: " + element.getAttribute("href")+ " returned " + isLinkBroken(new URL(element.getAttribute("href"))));
    }
}

参见评论&#34;这是我的递归试验&#34;。但它通过第一页,然后再通过第一页,这就是全部。

2 个答案:

答案 0 :(得分:1)

您正在尝试编写网络抓取工具。我是代码重用的忠实粉丝。也就是说我总是环顾四周,看看我的项目是否已经写完,然后才花时间自己编写。并且有很多版本的网络抓取工具。一个由Marilena Panagiotidou编写pops up early in a google search。退出进口,她的基本版本看起来像这样。

public class BasicWebCrawler {

private HashSet<String> links;

public BasicWebCrawler() {
    links = new HashSet<String>();
}

public void getPageLinks(String URL) {
    //4. Check if you have already crawled the URLs 
    //(we are intentionally not checking for duplicate content in this example)
    if (!links.contains(URL)) {
        try {
            //4. (i) If not add it to the index
            if (links.add(URL)) {
                System.out.println(URL);
            }
            //2. Fetch the HTML code
            Document document = Jsoup.connect(URL).get();
            //3. Parse the HTML to extract links to other URLs
            Elements linksOnPage = document.select("a[href]");
            //5. For each extracted URL... go back to Step 4.
            for (Element page : linksOnPage) {
                getPageLinks(page.attr("abs:href"));
            }
        } catch (IOException e) {
            System.err.println("For '" + URL + "': " + e.getMessage());
        }
    }
}

public static void main(String[] args) {
    //1. Pick a URL from the frontier
    new BasicWebCrawler().getPageLinks("http://www.mkyong.com/");
}
}

这里要注意的最重要的事情可能是递归是如何工作的。递归方法是自称的方法。上面的例子不是递归。您有一个方法findAllLinks,您在页面上调用一次,然后对页面中找到的每个链接调用一次。请注意Marilena的getPageLinks方法如何为在给定URL的页面中找到的每个链接调用一次。在调用自身时,它会创建一个新的堆栈帧,并从页面生成一组新的链接,并为每个链接再次调用一次等等。

关于递归函数的另一个重要注意事项是它何时停止调用自身。在这种情况下,Marilena的递归函数一直在调用自己,直到它找不到任何新的链接。如果您要抓取的页面链接到其域外的页面,则此程序可能会运行很长时间。而且,顺便说一下,在这种情况下可能发生的事情是这个网站得到它的名字:StackOverflowError

答案 1 :(得分:0)

确保您没有两次访问同一个网址。添加一些用于存储已访问过的URL的表。由于每个页面都可能以链接到主页的标题开头,因此您可能会一次又一次地访问它。