需求
最近在爬取一家网站的内容,但是发现这家网站的部分内容嵌入在css里,需要解析css 的值,所以用无头的chrome浏览器来抓取页面,利用chrome driver 解析网页,运行js 来提取网页内容。
技术方案采用 java 11 + selenium 4.7.2 + chrome driver 108
注意 windows 上 chrome driver 的版本要与 本机的chrome 版本一致。
chrome driver 下载地址 http://chromedriver.storage.googleapis.com/index.html?path=108.0.5359.71/
代码实现
pom.xml 依赖配置
<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>4.7.2</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-chrome-driver</artifactId> <version>4.7.2</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-api</artifactId> <version>4.7.2</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-remote-driver</artifactId> <version>4.7.2</version> </dependency>
crawl.java 主要 java 代码
Document doc = null; System.setProperty("webdriver.chrome.driver", "C:\\tmp\\chromedriver_win32_108\\chromedriver.exe"); //谷歌浏览器 ChromeOptions options = new ChromeOptions(); options.addArguments("--headless", "--window-size=1920,1200", "--disable-gpu", "--no-sandbox", "--disable-dev-shm-usage", "--no-sandbox"); options.setHeadless(true); options.setAcceptInsecureCerts(true); options.addArguments("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"); WebDriver driver = new ChromeDriver(options); driver.manage().timeouts().pageLoadTimeout(40, TimeUnit.SECONDS); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); //示例爬取url String htmlUrl = "https://xfunpark.com"; driver.get(htmlUrl); ((JavascriptExecutor) driver).executeScript(JS_SCRIPT); WebDriverWait webDriverWait = new WebDriverWait(driver, 10); webDriverWait.until(new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver webDriver) { JavascriptExecutor jsExecutor = (JavascriptExecutor) webDriver; Object res = jsExecutor.executeScript("\n;return checkPageReady()"); log.info("js checkPageReady() 返回:{}", res); return res != null && (Boolean) res; } }); JavascriptExecutor jsExecutor = (JavascriptExecutor) driver; String json = (String) jsExecutor.executeScript("return getOnePageData();"); log.info("结果显示:{}", json);
这里有个 JS_SCRIPT 变量,存储的是 是 JS 代码,由于传统的爬虫是 java/python 代码来获取dom元素来解析,这样太麻烦了,不优雅,
由于我们已经使用了 chrome driver,相当于一个chrome浏览器了,我们直接传给 chrome 一些解析dom的方法,返回值是我们想要的json,
再传给java,这样更为简洁优雅。示例的 JS_SCRIPT 如下 :
crawl.js (放在 classpath 下,直接读取文件为 字符串,传给 chrome)
给window 挂载两个方法,后面去调用她们。
//返回 #content_list 是否已经生成 window.checkPageReady = function(){ return document.getElementById('content_list') != undefined; } //获取这个页面上我们想要的数据为 json window.getOnePageData = function(){ let res = {}; res.title = document.getElementById("title").innerText; res.price = document.getElementById("price").innerText; return JSON.stringify(res); }
这里有个 webDriverWait ,这个是代表chrome 在等待一定条件之后再去往下执行,我们这里是检测 checkPageReady 是否返回true,返回true 了才去执行获取数据的方法。