in

如何通过网页爬取处理Ajax网站

今天,越来越多的网站正在使用Ajax,以获得花哨的用户体验,动态网页,以及更多的好理由。 抓取Ajax重的网站可能是棘手和痛苦的,我们将看到一些技巧,使其更容易。

准备条件

在开始之前,请阅读我之前写的文章,了解如何设置你的Java环境,并对HtmlUnitIntroduction to Web Scraping With JavaHandling Authentication有一个基本的了解。 阅读之后,你应该对Web Scraping更熟悉一些。


设    置

我们将看到的用Java爬取Ajax网站的第一个方法是通过使用PhantomJS与Selenium和GhostDriver。

PhantomJS是一个基于WebKit的无头网络浏览器(用于Chrome和Safari)。它的速度相当快,而且在渲染Dom方面做得很好,就像一个正常的网络浏览器一样。

  • 首先你需要下载PhantomJS
  • 然后把这个添加到你的pom.xml中。
    com.github.detro
    phantomjsdriver
    1.2.0

和这个:

   org.seleniumhq.selenium
    selenium-java
    2.53.1

##PhantomJS和Selenium

现在我们要使用Selenium和GhostDriver来 “引导 “PhantomJS。

我们将看到的例子是在一个新闻网站上的一个简单的 “查看更多 “按钮,执行ajax调用来加载更多的新闻。 所以你可能认为打开PhantomJS来点击一个简单的按钮是浪费时间和过度的?当然是这样的!

像往常一样,我们必须打开Chrome开发工具或你喜欢的检查器,看看如何选择 “加载更多 “按钮,然后点击它。

现在我们来看看一些代码:

private static String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36";
	private static DesiredCapabilities desiredCaps ;
	private static WebDriver driver ;
	
	
	public static void initPhantomJS(){
		desiredCaps = new DesiredCapabilities();
		desiredCaps.setJavascriptEnabled(true);
		desiredCaps.setCapability("takesScreenshot", false);
		desiredCaps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, "/usr/local/bin/phantomjs");
		desiredCaps.setCapability(PhantomJSDriverService.PHANTOMJS_PAGE_CUSTOMHEADERS_PREFIX + "User-Agent", USER_AGENT);

		ArrayList cliArgsCap = new ArrayList();
		cliArgsCap.add("--web-security=false");
		cliArgsCap.add("--ssl-protocol=any");
		cliArgsCap.add("--ignore-ssl-errors=true");
		cliArgsCap.add("--webdriver-loglevel=ERROR");

		desiredCaps.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, cliArgsCap);
		driver = new PhantomJSDriver(desiredCaps);
		driver.manage().window().setSize(new Dimension(1920, 1080));
	}

设置PhantomJs和Selenium的代码太多了!我建议你读一下文档,看看你可以传递给PhantomJS的许多参数。

注意,你必须用你自己的phantomJs可执行路径替换/usr/local/bin/phantomjs

然后在一个主方法中:

System.setProperty("phantomjs.page.settings.userAgent", USER_AGENT);
		String baseUrl = "https://www.inshorts.com/en/read" ;
		initPhantomJS();
		driver.get(baseUrl) ;
		int nbArticlesBefore = driver.findElements(By.xpath("//div[@class='card-stack']/div")).size();
		driver.findElement(By.id("load-more-btn")).click();
		
		// We wait for the ajax call to fire and to load the response into the page
		Thread.sleep(800);
		int nbArticlesAfter = driver.findElements(By.xpath("//div[@class='card-stack']/div")).size();
		System.out.println(String.format("Initial articles : %s Articles after clicking : %s", nbArticlesBefore, nbArticlesAfter));

在这里,我们调用initPhantomJs()方法来设置一切,然后我们用它的id选择按钮并点击它。

代码的另一部分是计算我们在页面上的文章数量,并打印出来,以显示我们已经加载了什么。

我们也可以用driver.getPageSource()打印出整个dom,并在真正的浏览器中打开它,看看点击前后的区别。

我建议你看一下Selenium Webdriver的文档,有很多很酷的方法来操作DOM。

我使用了一个肮脏的解决方案,用我的Thread.sleep(800)来等待Ajax调用完成。 它是肮脏的,因为它是一个任意的数字,如果我们可以只等待执行该Ajax调用的时间,刮刀可以运行得更快。

还有其他解决这个问题的方法。

public static void waitForAjax(WebDriver driver) {
    new WebDriverWait(driver, 180).until(new ExpectedCondition() {
        public Boolean apply(WebDriver driver) {
            JavascriptExecutor js = (JavascriptExecutor) driver;
            return (Boolean) js.executeScript("return jQuery.active == 0");
        }
    });
}

如果你看一下我们点击按钮时执行的功能,你会发现它使用的是jQuery。
这段代码将等待,直到变量jQuery.active等于0(这似乎是一个jQuery的内部变量,计算正在进行的ajax调用的数量)。

如果我们知道Ajax调用应该渲染哪些DOM元素,我们就可以在WebDriverWait条件中使用那个id/class/xpath:

wait.until(ExpectedConditions.elementToBeClickable(By.xpath(xpathExpression)))

[文中代码源自Scrapingbee]

总    结

所以我们已经看到了一点关于如何使用PhantomJS与Java的情况。当你有几十个Ajax调用,以及大量的Javascript被执行以正确渲染页面时,可能会很难抓取出你想要的数据,而PhantomJS/Selenium就是来拯救你的。

What do you think?

68

Written by 砖家

68web团队是一支专注于跨境业务和数据获取的专业团队。我们致力于帮助企业成功出海,通过高效的数据爬取服务,为客户提供精准的数据支持;

凭借丰富的经验和专业的技术,我们不仅提供多语言网站建设,还包括国际市场推广和定制化的跨境电商解决方案;

我们的数据爬取平台利用强大的服务器和代理IP,确保获取高质量的数据,以满足客户在AI和大数据时代的需求。我们专注于提供全面的解决方案,助力企业在全球市场上取得成功。

如何使用JSoup在Java中解析HTML

如何使用Charles代理进行网页爬取