爬虫

网络爬虫,是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。

爬虫分类

网页去重

海明距离

在信息编码中,两个合法代码对应位上编码不同的位数称为码距,又称海明距离。举例如下:10101和00110从第一位开始依次有第一位、第四、第五位不同,则海明距离为3

运行方式

  1. 起始爬行页面集合:通过手动指定或者自动化的方式,是爬虫的种子列表
  2. 从起始爬行页面提取链接,对链接规范化,处理掉链接的别名(如url里的hash),并将相对链接转为绝对链接,加入爬行列表
  3. 减少爬取环路,使用哈希表、布隆过滤器等过滤爬取过的页面,并且要将这些数据持久化

环路减少策略

robots.txt

版本 说明
0.0 支持Disallow指令 禁止爬行
1.0 支持Allow指令 允许爬行
2.0 新增正则表达式及定时功能

格式

# 注释: 禁止百度蜘蛛和谷歌蜘蛛爬取/admin
User-Agent: baidu-spider
User-Agent: google-spider
Disallow: /admin

# 禁止所有蜘蛛爬取/super-admin
User-Agent: *
Disallow: /super-admin

url的匹配是前缀匹配

爬虫META指令

<meta name='robots' content='noindex'>

content可取值如下:

给搜索引擎的META标签

<meta name='description' content="页面描述">
<meta name='keywords' content="关键词1, 关键词2">
<!-- 10天后再来爬一次 -->
<meta name='revisit-after' content="10 days">

使用Java爬

HttpClient

Get请求

HttpGet get = new HttpGet("http://www.baidu.com");

try (CloseableHttpClient client = HttpClients.createDefault();
    CloseableHttpResponse response = client.execute(get)) {
    String s = EntityUtils.toString(response.getEntity(), "utf8");
    System.out.println(s);
}
URIBuilder uriBuilder = new URIBuilder("http://www.baidu.com/s").addParameter("wd", "关键词");
HttpGet get = new HttpGet(uriBuilder.build());

POST请求

var request = new HttpPost("http://example");
var pairs = List.of(new BasicNameValuePair("keys", "java"), new BasicNameValuePair("keys", "python"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairs, "utf8");
request.setEntity(entity);

连接池

PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
// 最大连接数
manager.setMaxTotal(100);
// 每个主机最大连接数
manager.setDefaultMaxPerRoute(10);
CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).build();

请求参数

RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) // 获取连接的最长时间,单位ms
  .setConnectionRequestTimeout(500) // 获取连接的最长时间
  .setSocketTimeout(10000).build(); // 传输数据最长时间
HttpGet get = new HttpGet();
get.setConfig(config);

Jsoup

DOM

Document doc = Jsoup.parse(new URL("http://www.baidu.com"), 10000);
doc.getElementByXXX();

元素API

Element e = doc.getElementById("login");
        System.out.println(e.id());
        System.out.println(e.className());
        System.out.println(e.classNames());
        System.out.println(e.text());
        System.out.println(e.attr("style"));
        System.out.println(e.attributes());

使用CSS选择器

doc.select("div")
    .forEach(System.out::println);

WebMagic

使用

public class JobProcessor implements PageProcessor {

    private Site site = Site.me().addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36");

    @Override
    public void process(Page page) {
        page.putField("div1",page.getHtml().css("#logo-2014").get());
        page.putField("div2",page.getHtml().xpath("//div").get());

    }

    @Override
    public Site getSite() {
        return site;
    }
}
Spider.create(new JobProcessor())
    .addUrl("https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&wq=%E6%89%8B%E6%9C%BA&pvid=9524dc8e0e2d45f08656f023fa60a0de")
    .run();

元素抽取

page.putField("div1",page.getHtml().css("#logo-2014").get()); // 获取一条
        page.putField("div2",page.getHtml().xpath("//div[@id=logo-2014]").all());  // 获取全部

获取链接

page.getHtml().links()
page.addTargetRequests(page.getHtml().links().all());

输出数据

Spider.create(new JobProcessor())
  .addUrl("url")
  .addPipeline(new FilePipeline("./result.txt"))
  .run();

Site

Scheduler

Spider.create(null)
                .setScheduler(new QueueScheduler().setDuplicateRemover(new BloomFilterDuplicateRemover(100000)));
三种去重方式

文档

使用代理

downloader.setProxyProvider(new SimpleProxyProvider(List.of(new Proxy("116.114.19.211",443))));
Spider.create(new ProxyProcessor())
  .addUrl("http://ip-api.com/json/?lang=zh-CN")
  .setDownloader(downloader)
  .run();