关于java爬虫的一些学习记录

一.创建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中,反正有数据拿到了怎么舒服怎么来!!
        }

    }
}到这里也就基本上可以做一些小爬虫的程序了,再见
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值