618薅某电商网站羊毛做私人数据储备

125 阅读4分钟

最近快618了,各大电商都开始做促销,想必服务器性能很厉害能顶得住亿万级别的访问量。趁这时候我想对某个电商网站进行网络爬虫,爬取一定量的商品数据来做我自己的数据储备。

ps:只做个人数据储备,不对外开放,只用作个人学习使用。

爬虫框架选型

笔者主要是Java开发,也有写过一些python工具,但是python已经很久没写了所以选择Java相关的爬虫框架。

Java网络爬虫框架种类

  1. Gecco 代码地址
  2. WebCollector代码地址
  3. Spiderman代码地址
  4. WebMagic代码地址

等等等等,还有很多简单易用的框架。

因为笔者一直使用的是WebMagic,所以这次网络爬虫就选择使用WebMagic这个框架技术。

爬虫代码以及单元测试

总体结构

image.png

Downloader

Downloader负责从互联网上下载页面,以便后续处理。WebMagic默认使用了Apache HttpClient作为下载工具。

PageProcessor

PageProcessor负责解析页面,抽取有用信息,以及发现新的链接。WebMagic使用Jsoup作为HTML解析工具,并基于其开发了解析XPath的工具Xsoup

在这四个组件中,PageProcessor对于每个站点每个页面都不一样,是需要使用者定制的部分。

Scheduler

Scheduler负责管理待抓取的URL,以及一些去重的工作。WebMagic默认提供了JDK的内存队列来管理URL,并用集合来进行去重。也支持使用Redis进行分布式管理。

除非项目有一些特殊的分布式需求,否则无需自己定制Scheduler。

Pipeline

Pipeline负责抽取结果的处理,包括计算、持久化到文件、数据库等。WebMagic默认提供了“输出到控制台”和“保存到文件”两种结果处理方案。

Pipeline定义了结果保存的方式,如果你要保存到指定数据库,则需要编写对应的Pipeline。对于一类需求一般只需编写一个Pipeline

官方文档对四大组件进行了详细的解析,并且给出了相关的例子,感兴趣可以去看一下。

核心代码

测试爬取的页面

使用api请求工具对要爬取的链接发起请求,查看返回的是json串还是html页面

如果是html页面那就要分析页面进行爬取,如果返回的是json串那比较简单,只须提取特定字段即可。

image.png

这里我查找了一些python的商品,好庆幸返回的是json串,这样我只需要抽取特殊字段就可以了。

爬虫代码

依赖

<dependency>
    <groupId>us.codecraft</groupId>
    <artifactId>webmagic-core</artifactId>
    <version>0.7.4</version>
</dependency>
<dependency>
    <groupId>us.codecraft</groupId>
    <artifactId>webmagic-extension</artifactId>
    <version>0.7.4</version>
</dependency>

强烈推荐使用0.7.4或以上的依赖,因为0.7.4以下的包体在爬取https网站的时候会有ssl错误,需要手动改写代码,以下是github的issues

image.png

页面解析

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "goods")
public class shop {
    @Id
    private String id;
    private String ad_title;
    private String color;
    private String fuzzy_comment_num;
    private String link_url;
    private String shop_link;
}
@Slf4j
public class webCatch implements PageProcessor {
    //设置重试时间和休眠时间
    private Site site = Site.me().setRetryTimes(3).setSleepTime(100);
    List<shop> shops = new ArrayList<>(10);

    /**
     * 自定义数据抽取类
     * @param page
     */
    @Override
    public void process(Page page) {
        //设置字符集
        site.setCharset("utf-8");
        String resultJson = page.getJson().toString();
        Map map = JSONObject.parseObject(resultJson);
        List<shop> userList = JSONObject.parseArray(map.get("291").toString(), shop.class);
        for (shop  u: userList) {
            //对数据分析并且抽取处理相关字段
            u.setAd_title(u.getAd_title().replace("<font class=\"skcolor_ljg\">","").replace("</font>",""));
            shops.add(u);
        }
        log.info(shops.toString());
    }

    @Override
    public Site getSite() {
        return site;
    }
}

爬虫启动类

public static void main(String[] args) {
    String keyword="手机";
    Spider.create(new webCatch()).addUrl("你的爬虫url")
            .thread(1).run();
}

结果

image.png ok,已经成功抽取到结果并且输出到控制台了。

集成elasticsearch

我将爬取到的数据持久化到es,然后再通过es同步到mysql做一个数据储备。

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

配置以及代码

yml配置

spring:
  elasticsearch:
    rest:
      uris: 你的elasticsearch地址

持久层

public interface shopMapper extends ElasticsearchRepository<shop,String> {

}

业务层

public void saveData(List<shop> data) {
    shopMapper.saveAll(data);
}

爬虫Pipeline处理类

@Slf4j
@Component
public class DetailPipeline implements Pipeline {
    @Autowired
    private shopService shopService;
    @Override
    public void process(ResultItems resultItems, Task task) {
        List<shop> shopList = resultItems.get("result");
        for (shop s:shopList ) {
            log.info(s.getShop_link());
            log.info(s.getAd_title());
            log.info(s.getColor());
            log.info(s.getLink_url());
            log.info(s.getFuzzy_comment_num());
        }
        shopService.saveData(shopList);
    }
}

启动类改造

@Autowired
DetailPipeline DetailPipeline;

@Test
void getWebMagci() throws InterruptedException {
    String keyword="手机";
    int page=1;
    for (int i = page; i <=5; i++) {
        Spider.create(new webCatch()).addUrl("url地址")
                   //添加自定义处理类
                .addPipeline(this.DetailPipeline)
                .addPipeline(new FilePipeline("D:\webmagic"))//保存爬取的网页到本地以便后续操作
                .addPipeline(new JsonFilePipeline("D:\webmagic\json"))//保存json文件
                .thread(1)//开启多少条线程,注意别太多
                .run();
        page++;
        Thread.sleep(1000);//线程休眠,让服务器缓缓
    }
}

测试结果

image.png

kibana数据可视化

可视化

进入kibana管理页面,并且点击侧栏进入Discover

image.png

进入Discover

image.png

选择相关的索引后即可看到命中的数据。

关联索引

如果你是第一次使用kibana,请按照以下步骤关联索引

  1. 点击侧栏底部的Stack Management

image.png

  1. 点击索引模式

image.png

  1. 点击右上角创建索引模式

image.png

  1. 填写es的索引名匹配源

image.png

点击下一步,然后创建即可。

ok,fine! 到这里就基本大功告成了,剩下的就是启动一个定时任务就可以进行爬取数据了。

总结以及注意事项

PS:再次声明,此数据仅为个人学习使用,绝不对外公开

难点

对页面的分析以及抽取是难点,每个人爬取的网站与需求都不一样,要看具体业务需求而定,耐心很重要,多尝试观察返回的结果规则。

如果返回的是json串那就很简单了,如果是返回html页面,则必须对页面进行分析,使用Selectable进行过滤与抽取。

具体抽取方法请查看WebMagic官方文档

注意事项

注意爬虫的线程以及休眠,不要过分请求服务器以免把服务器搞崩,爬取到的数据切勿倒卖,如触犯法律均与作者无关。请勿使用网络爬虫进行违法犯罪活动!!!!