Web抓取或抓取是通过下载并解析HTML代码以提取所需数据来从第三方网站获取数据的事实。
由于每个网站都不提供干净的API或根本不提供API,因此在提取网站信息时,网络抓取可能是唯一的解决方案。
许多公司都使用它来获取有关竞争对手价格,新闻汇总和大量电子邮件收集的知识……
几乎所有内容都可以从HTML中提取,唯一“难以提取”的信息是图像或其他媒体内部。
在这篇文章中,我们将看到基本的技术,以便在Java中获取和解析数据。
本文摘自我的新书《 Java Web Scraping Handbook》 。 这本书将教您网络抓取的崇高艺术。 从解析HTML到打破验证码,处理Javascript繁重的网站等等。
先决条件
- 基本的Java知识
- 基本XPath
您将需要带有HtmlUnit的 Java 8
< dependency >
< groupId > net.sourceforge.htmlunit </ groupId
< artifactId > htmlunit </ artifactId >
< version > 2.19 </ version >
</ dependency >
如果您使用的是Eclipse,建议您在详细信息窗格中(当您单击“变量”选项卡时)配置最大长度,以便您可以看到当前页面的整个HTML。
让我们刮一下CraigList
对于第一个示例,我们将从CraigList中获取项目,因为它们似乎不提供API,无法收集名称,价格和图像并将其导出为JSON。
首先,让我们看一下在CraigList上搜索项目时会发生什么。 打开Chrome Dev工具,然后点击“网络”标签:
搜索网址为: https://newyork.craigslist.org/search/moa?is_paid=all&search_distance_type=mi&query=iphone+6s
: https://newyork.craigslist.org/search/moa?is_paid=all&search_distance_type=mi&query=iphone+6s
您还可以使用https://newyork.craigslist.org/search/sss?sort=rel&query=iphone+6s
现在您可以打开自己喜欢的IDE了,该进行编码了。 HtmlUnit需要WebClient发出请求。 有很多选项(代理设置,浏览器,已启用重定向...)
我们将禁用Javascript,因为我们的示例不需要使用Javascript,并且禁用Javascript可加快页面加载速度:
String searchQuery = "Iphone 6s" ;
WebClient client = new WebClient();
client.getOptions().setCssEnabled( false );
client.getOptions().setJavaScriptEnabled( false );
try {
String searchUrl = "https://newyork.craigslist.org/search/sss?sort=rel&query="
+ URLEncoder.encode(searchQuery, "UTF-8" );
HtmlPage page = client.getPage(searchUrl);
} catch (Exception e){
e.printStackTrace();
}
HtmlPage对象将包含HTML代码,您可以使用asXml()
方法访问它。
现在,我们将获取标题,图像和价格。 我们需要检查项目的DOM结构:
使用HtmlUnit,您可以选择几个选项来选择html标签:
-
getHtmlElementById(String id)
-
getFirstByXPath(String Xpath) - getByXPath(String XPath)
返回列表的getFirstByXPath(String Xpath) - getByXPath(String XPath)
- 还有很多,rtfm!
由于没有可用的ID,我们必须制作一个Xpath表达式来选择所需的标签。
XPath是一种查询语言,用于选择XML节点(在本例中为HTML)。
首先,我们将选择所有具有类`result-info`
的<p>
标签。
然后,我们将遍历此列表,并为每个项目选择名称,价格和url,然后打印出来。
List<HtmlElement> items = (List<HtmlElement>) page.getByXPath( "//li[@class='result-row']" ) ;
if (items.isEmpty()){
System.out.println( "No items found !" );
} else {
for (HtmlElement htmlItem : items){
HtmlAnchor itemAnchor = ((HtmlAnchor) htmlItem.getFirstByXPath( ".//p[@class='result-info']/a" ));
HtmlElement spanPrice = ((HtmlElement) htmlItem.getFirstByXPath( ".//a/span[@class='result-price']" )) ;
// It is possible that an item doesn't have any price, we set the price to 0.0 in this case
String itemPrice = spanPrice == null ? "0.0" : spanPrice.asText() ;
System.out.println( String.format( "Name : %s Url : %s Price : %s" , itemName, itemPrice, itemUrl));
}
}
然后,我们将不只是打印结果,而是使用Jackson库将其放入JSON中,以JSON格式映射项目。
首先,我们需要一个POJO(普通的旧Java对象)来表示Items
Item.java
public class Item {
private String title ;
private BigDecimal price ;
private String url ;
//getters and setters
}
然后将其添加到您的pom.xml
:
< dependency >
< groupId > com.fasterxml.jackson.core </ groupId >
< artifactId > jackson-databind </ artifactId >
< version > 2.7.0 </ version >
</ dependency >
现在,我们要做的就是创建一个Item,设置其属性,并将其转换为JSON字符串(或文件…),然后稍微修改一下先前的代码:
for (HtmlElement htmlItem : items){
HtmlAnchor itemAnchor = ((HtmlAnchor) htmlItem.getFirstByXPath( ".//p[@class='result-info']/a" ));
HtmlElement spanPrice = ((HtmlElement) htmlItem.getFirstByXPath( ".//a/span[@class='result-price']" )) ;
// It is possible that an item doesn't have any price, we set the price to 0.0 in this case
String itemPrice = spanPrice == null ? "0.0" : spanPrice.asText() ;
Item item = new Item();
item.setTitle(itemAnchor.asText());
item.setUrl( baseUrl + itemAnchor.getHrefAttribute());
item.setPrice( new BigDecimal(itemPrice.replace( "$" , "" )));
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(item) ;
System.out.println(jsonString);
}
走得更远
这个例子并不完美,有很多地方可以改进:
- 多城市搜寻
- 处理分页
- 多条件搜索
您可以在此Github存储库中找到代码
希望您喜欢这篇文章,并随时在评论中给我反馈。
本文摘自我的新书: Java Web Scraping Handbook 。 这本书将教您网络抓取的崇高艺术。 从解析HTML到打破验证码,处理Javascript繁重的网站等等。
From: https://hackernoon.com/introduction-to-web-scraping-with-java-3d8a8d0f250b