本文中使用的HttpClient是在apache HttpClient的基础上封装的class,文章末尾会给出源码分享
- 思路:首先我们用HttpClient模拟请求,获取到html代码,用jsoup解析过滤html,获取我们想要的数据。
- 场景描述:因为我要抓取这个网站所有分页的数据,我在用HttpClient模拟请求之前,在chrome中直接访问url,发现请求被重定向?这就很麻烦了!
- 分析:正常我们通过
window.location.href
发出的request请求Referer
这个参数都会有值,当我们通过其他方式访问的时候(浏览器直接访问,HttpClient)这个参数值为null
防盗链大致代码如下:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String referer = req.getHeader("referer");
//window.location.href
if(null != referer && (referer.trim().startsWith("http://localhost:8033")||referer.trim().startsWith("http://www.zhihuidaojia.cn/"))){
System.out.println("正常页面请求"+referer);
chain.doFilter(req, resp);
//其他方式请求,例如浏览器输入地址,或者我们的爬虫
}else{
System.out.println("盗链"+referer);
req.getRequestDispatcher("/LdapLogin.jsp").forward(req, resp);
}
}
防盗链的作用限制你只能在浏览器端通过类似window.location.href
这种请求去访问,禁止其他方式请求,所以我们只需要在请求的时候模拟这个参数就ok了!
下面看核心代码
maven
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient -->
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
模拟请求
public void catchHy88() throws Exception{
for (int i=1; i<508; i++) {
log.info("循环开始,当前索引:" + i);
String url = "http://www.abc.com/search.html?kw=大连金州&type=company&page=PAGE_NUM/";
HttpClient httpClient = new HttpClient(url.replace("PAGE_NUM", Integer.toString(i)));
//设置referer参数,绕过防盗链
httpClient.setReferer("www.abc.com");
//获取html
String html = httpClient.request();
log.info("接收到返回的html消息,开始筛选数据");
//处理html 获取data
HY88Converter hy88Converter = HY88Converter.getInstance();
List<Company> list = hy88Converter.html2Company(html, i);
//批量执行数据库操作,当List长度为N时
companyMapper.batchInsert(list);
}
}
这时候已经获取html代码了,可以开始抓取数据了
先分析页面结构
我需要的数据,全在<div class="conttext">
中,所以我们要获取所有的<div class="conttext">
,然后遍历
具体代码为:
Elements elements = doc.select("div.conttext")
然后遍历Elements,进一步筛选。
jsoup 语法类似 jquery,相比用正则表达式,我觉得这种方式更便捷一些吧
下面是我的源码
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import com.taven.web.hy88crawler.entity.Company;
public class HY88Converter {
private static HY88Converter instance = null;
/**
* 返回单例
*
* @return
*/
public static HY88Converter getInstance() {
if (instance == null)
instance = new HY88Converter();
return instance;
}
/**
* 将抓取到的html信息转为公司实体
*
* @param html
*/
public List<Company> html2Company(String html, Integer currentPage) {
List<Company> companyList = new ArrayList<Company>();
Document doc = Jsoup.parse(html);
Elements elements = doc.select("div.conttext");
for (Element element : elements) {
try {
String phoneStr = element.select("li[class=com]:contains(电话号码)").text();
String phone = phoneStr.replace("电话号码", "");
//如果包含 - 说明是座机 执行下一次
if (StringUtils.isBlank(phone) || phone.contains("-") )
continue;
String contact = element.select("li[class=fen]").text();
if (StringUtils.isBlank(contact))
continue;
String name = element.select("p[class=p-title]").select("a").attr("title");
companyList.add(new Company(name, phone, contact, currentPage));
} catch (Exception e) {
continue;
}
}
return companyList;
}
}
转载请注明出处,原文作者:殷天文
HttpClient工具类源码 链接: https://pan.baidu.com/s/1mkl9yL6 密码: hfzv
参考文献
jsoup 中文api
HttpClient参考博客,感谢原作者