一.创建HttpClient工具类(底层代码)
@Component
public class HttpUtils {
private PoolingHttpClientConnectionManager cm;
public HttpUtils() {
this.cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(100);
cm.setDefaultMaxPerRoute(10);
}
public String doGetForElement(String url){
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.cm).build();
HttpGet httpGet = new HttpGet(url);
httpGet.setConfig(this.getRequestConfig());
CloseableHttpResponse httpResponse = null;
try {
httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode()==200){
if(httpResponse.getEntity()!=null){
String element = EntityUtils.toString(httpResponse.getEntity(),"gb2312");
return element;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return "";
}
public RequestConfig getRequestConfig(){
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(1000)
.setConnectionRequestTimeout(1000)
.setSocketTimeout(60*1000)
.build();
return requestConfig;
}
}
二、调用工具类实现调用(测试用例)
package club.loserblog.reptile;
import club.loserblog.reptile.club.loserblog.util.HttpUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.UnsupportedEncodingException;
@SpringBootTest
class ReptileApplicationTests {
@Autowired
HttpUtils httpUtils;
@Test
void test(){
String str = "%68%74%74%70%73%3A%2F%2F%76%33%2E%74%74%73%70%34%34%2E%76%69%70%3A%38%38%31%2F%32%67%63%2F%47%43%36%32%57%45%52%2F%47%43%36%32%57%45%52%32%2E%6D%33%75%38";
System.out.println(this.getURLDecoderString(str));
}
@Test
void contextLoads() {
for(int i = 2;i<=67;i++){
String element = httpUtils.doGetForElement("https;//www.baidu.com");
Document document = Jsoup.parse(element);
Element content = document.getElementsByClass("myvod").first();
Elements elements = content.select("ul > li");
for (Element item : elements){
//获取titile
String title = item.getElementsByTag("a").first().attr("title");
//获取网络图片地址
String pic = item.getElementsByTag("a").first().getElementsByTag("img").first().attr("data-original");
//获取本地图片地址
String localPic = httpUtils.doGetForResource(pic);
//获取详情页面地址
String detail = "https://www.baidu.com" + item.getElementsByTag("a").first().attr("href");
String videlSrc = null;
try {
String str = this.getVideoSrc(detail).replace("\"","");
videlSrc = "https://www.baidu.com" + "/1/index.html?url=" + str;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
System.out.println("标题: "+title +" 本地图片: "+localPic + "视频地址:"+videlSrc) ;
}
}
}
/**
* 获取详情页面的视频地址
* @param url
* @return
*/
private String getVideoSrc(String url) throws JsonProcessingException {
String element = httpUtils.doGetForElement(url);
Document document = Jsoup.parse(element);
String videoSrc = document.getElementsByClass("myplayer").first().html();
String srcJson = videoSrc.substring(videoSrc.lastIndexOf("{"),videoSrc.lastIndexOf("}")+1);
ObjectMapper objectMapper = new ObjectMapper();
String encryptionUrl = objectMapper.readTree(srcJson).get("url").toString();
return this.getURLDecoderString(encryptionUrl);
}
public static String getURLDecoderString(String str) {
String result = "";
if (null == str) {
return "";
}
try {
result = java.net.URLDecoder.decode(str, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
}
如何使用webmagic
1、导入jar包(如果接口PageProcessor报红,问题就是jar没有导入成功 [网络不好jar包会下载不来下来,所以别折腾换个好一点网络环境])
<!-- webmagic 核心jar包 -->
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-core</artifactId>
<version>0.7.3</version>
</dependency>
<!-- 布隆过滤器所依赖的工具包 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
<!-- webmagic扩展包 -->
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>0.7.3</version>
<!-- 不导入扩展包中的slf4j的jar包,避免jar包冲突 -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
2、实现PageProcessorProcessor接口,其中包含两个方法,process()用于解析页面,getSite()对请求的一些配置。
public class CSDNUtil implements PageProcessor {
@Override
public void process(Page page) {
//解析页面
//解析页面一般都是要判断的,如果没有数据列表那么可能是详情页,如果有数据列表那么可以就是首页列表,将详情页加入
//请求队列,请求队列类似于循环调用某个方法一样,所以为了效率和性能考虑一般不通用的代码还是加上判断的好
//如何将解析的结果放入保存队列中呢
page.putField("key",value);
//怎么添加详情页面的地址呢
page.addTargetRequest(links);
}
private Site site = Site.me();
@Override
public Site getSite() {
//设置编码格式(获取页面元素的编码,最好是f12去页面查看请求页面的编码格式,防止获取的页面中文内容乱码)
this.site.setCharset("utf-8")
.setTimeOut(10*10000) //设置超时时间
.setRetrySleepTime(3000) //设置重试时间(请求超过多长时间开启重试)
.setRetryTimes(3); //设置重试次数
return this.site;
}
public static void main(String[] args) {
//创建下载器对象
HttpClientDownloader httpClientDownloader = new HttpClientDownloader();
//设置代理服务器信息
httpClientDownloader.setProxyProvider(SimpleProxyProvider.from(
new Proxy("101.101.101.101",8888)
,new Proxy("102.102.102.102",8888)));
Spider.create(new CSDNUtil())
.addUrl("https://blog.csdn.net/qq_36259025") //设置爬虫地址
//选择布隆过滤器实现去重
.setScheduler(new QueueScheduler().setDuplicateRemover(new BloomFilterDuplicateRemover(100000)))
.thread(10) //设置启动线程数
.addPipeline(new TestPageline())//配置保存后的数据处理
.setDownloader(httpClientDownloader) //设置已经配置了代理的下载器
.run();
}
}
常用获取结果的方法如下
方法名称 | 描述 | 返回值 |
---|---|---|
toString() | 获取元素的第一个 | String |
get() | 和toString一样的都是获取第一个元素 | String |
all() | 获取所有的元素(获取的结果为String,也就是说拿到结果之后无法再次使用选择器进行选择了) | List<String> |
常用选择器api如下
描述 | 描述 | 返回值 |
---|---|---|
nodes() | 获取所有的元素节点 | List<Selectable> |
links() | 获取所有的链接(后续all和nodes区别为返回结果不一致all()返回String,nodes返回List<Selectable>) | Selectable |
css() | 通过css选择器获取满足条件的元素 | Selectable |
$() | 和css选择器差不多,但是可以获取元素的属性值如 [ .$("a#link","href") ] | Selectable |
获取元素的方式有多个,不止css选择器,也可以使用xpath、正则表达式
接下来就看一下怎么实现Pipeline
public class TestPageline implements Pipeline { @Override public void process(ResultItems resultItems, Task task) { //获取解析后保存的数据
String title = resultItems.get("title"); //判断是否为空
if(!"".equals(title)){ //处理方案,看你自己想怎么搞例如保存到mysql或者sqlserver中,反正有数据拿到了怎么舒服怎么来!! } } }
到这里也就基本上可以做一些小爬虫的程序了,再见