webmagic爬虫-java使用

1 篇文章 0 订阅

目录

 

介绍:

特性:

开发前,先弄懂webmagic四大组件以及架构图

架构图

四大组件: 

项目只是简单的爬虫,简单的涉及到process、Scheduler和Pipeline

1. pom.xml

2.常量类 常用的正则表达式

3.processor

3. pipeline

3.1 

3.2 控制台输出

3.3 文件输出


介绍:

WebMagic是一个简单灵活的Java爬虫框架。基于WebMagic,你可以快速开发出一个高效、易维护的爬虫。

特性:

  • 简单的API,可快速上手

  • 模块化的结构,可轻松扩展

  • 提供多线程和分布式支持

详细介绍和相关开发请看

官网:http://webmagic.io/

中文开发文档:http://webmagic.io/docs/zh/

开发前,先弄懂webmagic四大组件以及架构图

架构图

四大组件: 

1).Downloader:

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

2).PageProcessor

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

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

3).Scheduler

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

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

4).Pipeline

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

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

 

以下代码是我自己学习实例,如果有错,请指出。

项目只是简单的爬虫,简单的涉及到process、Scheduler和Pipeline

项目结构如下:

1. pom.xml

引入webmagic坐标

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

注意:

此jar包已包含slf4j-log4j12的jar包,故不要再次导入slf4j-log4j12包,引起jar包冲突

如果自己定制了slf4j的实现,请在项目中去掉此依赖。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.mzp</groupId>
	<artifactId>SpiderCSDN</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<properties>
		<!-- spring版本号 -->
		<spring.version>4.3.8.RELEASE</spring.version>
		<!-- aspectj版本号 -->
		<aspectj.version>1.6.12</aspectj.version>
		<!-- jstl标签版本 -->
		<jstl.version>1.2</jstl.version>
		<!-- mybatis版本号 -->
		<mybatis.version>3.4.5</mybatis.version>
		<!-- mybatis-spring整合包版本 -->
		<mybatis.spring.version>1.3.1</mybatis.spring.version>
		<!-- mysql版本号 -->
		<mysql.version>5.1.30</mysql.version>
		<!-- dbcp数据源连接池jar包 -->
		<dbcp.version>1.2.2</dbcp.version>
		<!-- log4j日志包版本 -->
		<slf4j.version>1.7.7</slf4j.version>
		<log4j.version>1.2.17</log4j.version>
		<!-- commons-lang版本 -->
		<commons.lang.version>2.6</commons.lang.version>

		<!-- 文件上传包版本 -->
		<fileupload.version>1.3.1</fileupload.version>
		<commonsio.version>2.4</commonsio.version>
		<commonscodec.version>1.9</commonscodec.version>

		<!-- 分页助手版本 -->
		<pagehelper.version>4.1.6</pagehelper.version>
		<jsqlparser.version>0.9.6</jsqlparser.version>
		<!-- 通用mapper版本 -->
		<!-- <tk.mybatis.version>3.4.6</tk.mybatis.version> -->
		<tk.mybatis.version>4.0.0</tk.mybatis.version>

		<!-- json支持,jackson包版本 -->
		<jackson.version>2.7.4</jackson.version>

		<!-- shiro -->
		<shiro.version>1.2.3</shiro.version>

		<!-- commons.logging -->
		<commons.logging.version>1.2</commons.logging.version>

		<!-- 注意,该jar包已包含基础的mybatis,故不需要再次引入mybatisjar包 -->
		<mybatis.plus.version>2.1.9</mybatis.plus.version>
	</properties>

	<dependencies>
		<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>26.0-jre</version>
		</dependency>

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


		<!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient -->
		<dependency>
			<groupId>commons-httpclient</groupId>
			<artifactId>commons-httpclient</artifactId>
			<version>3.1</version>
		</dependency>

		<!-- 注意,该jar包已包含基础的mybatis,故不需要再次引入mybatisjar包 -->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus</artifactId>
			<version>${mybatis.plus.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>${shiro.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-ehcache</artifactId>
			<version>${shiro.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-web</artifactId>
			<version>${shiro.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<!-- alibaba json -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.47</version>
		</dependency>

		<!-- 分页助手 -->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper</artifactId>
			<version>${pagehelper.version}</version>
		</dependency>
		<dependency>
			<groupId>com.github.jsqlparser</groupId>
			<artifactId>jsqlparser</artifactId>
			<version>${jsqlparser.version}</version>
		</dependency>

		<!-- 通用mapper -->
		<!-- <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> 
			<version>${tk.mybatis.version}</version> </dependency> -->

		<!-- commons-lang3 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.4</version>
		</dependency>

		<!-- springmvc依赖包 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>${aspectj.version}</version>
		</dependency>
		<!-- JSTL标签类 -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>
		<!-- mybatis核心包 -->
		<!-- <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> 
			<version>${mybatis.version}</version> </dependency> -->
		<!-- mybatis-spring整合包 -->
		<!-- <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> 
			<version>${mybatis.spring.version}</version> </dependency> -->
		<!-- 导入Mysql数据库链接jar包 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.version}</version>
		</dependency>
		<!-- 导入dbcp数据源连接池jar包 -->
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>${dbcp.version}</version>
		</dependency>
		<!-- 日志文件管理包 -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency><!-- <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> 
			<version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> 
			<artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> 
			</dependency> -->

		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>${commons.lang.version}</version>
		</dependency>

		<!-- logging包 -->
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>${commons.logging.version}</version>
		</dependency>

		<!-- jsp依赖包,只在编译时需要 -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
			<scope>provided</scope>
		</dependency>

		<!-- 文件上传组件包 -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>${fileupload.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>${commonsio.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>${commonscodec.version}</version>
		</dependency>

		<!-- jackson依赖包 -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-annotations</artifactId>
			<version>${jackson.version}</version>
		</dependency>

	</dependencies>

	<build>
		<finalName>${project.artifactId}</finalName>

		<plugins>
			<!-- 资源文件拷贝插件 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-resources-plugin</artifactId>
				<version>2.7</version>
				<configuration>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
			<!-- java编译插件 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.2</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
		<pluginManagement>
			<plugins>
				<!-- 配置Tomcat插件 -->
				<plugin>
					<groupId>org.apache.tomcat.maven</groupId>
					<artifactId>tomcat7-maven-plugin</artifactId>
					<version>2.2</version>
					<configuration>
						<!-- tomcat 的端口号 -->
						<port>8090</port>
						<!-- 访问应用的路径 -->
						<path>/</path>
						<!-- URL按UTF-8进行编码,解决中文参数乱码 -->
						<uriEncoding>UTF-8</uriEncoding>
						<!-- tomcat名称 -->
						<server>tomcat7</server>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
		<resources>
			<!-- 使用Maven部署的时候,xml和properties配置文件也一起部署到Tomcat -->
			<resource>
				<directory>src/main/java</directory>
				<includes>
					<include>**/*.properties</include>
					<include>**/*.xml</include>
				</includes>
				<filtering>false</filtering>
			</resource>
			<!-- 默认是以下配置 -->
			<resource>
				<directory>src/main/resources</directory>
				<includes>
					<include>**/*.*</include>
				</includes>
				<filtering>false</filtering>
			</resource>
		</resources>
	</build>
</project>

2.常量类 常用的正则表达式

package com.mzp.csdn;

import java.io.Serializable;

public interface SpiderConstant extends Serializable {

	// 规则页
	final static String CSDN_URL_REGEXP = "https://blog.csdn.net/.+";
	// 首页
	final static String CSDN_HOMEPAGE = "https://www.csdn.net/";
	// 首页分类匹配
	final static String CSDN_HOMEPAGE_REGEXP = "https://www.csdn.net/.+/.+";
	// 文章article
	final static String CSDN_ARTICLE = "https://blog.csdn.net/.+/article/details/\\d+";
	// 游戏开发
	final static String CSDN_GAME = "https://www.csdn.net/nav/game";
	// 数据库
	final static String CSDN_DB = "https://www.csdn.net/nav/db";
	// 广告
	final static String CSDN_AD = "";
	// 其他
	final static String CSDN_OTHER = "";

}

3.processor

注意该processor的main方法中也有Scheduler

package com.mzp.csdn.spider;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import com.mzp.csdn.SpiderConstant;
import com.mzp.csdn.service.SpiderService;
import com.mzp.csdn.spider.pipeline.impl.CsdnConsolePipeline;

import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.scheduler.BloomFilterDuplicateRemover;
import us.codecraft.webmagic.scheduler.FileCacheQueueScheduler;

public class CsdnProcessor implements PageProcessor, SpiderConstant {

	// 不符合CSDN网址规则的其他连接
	public static HashMap<String, String> otherUrlMap = new LinkedHashMap<String, String>();

	public static Map<String,Object> map = new LinkedHashMap<String,Object>();
	
	@Autowired
	private SpiderService spiderService;

	// 部分一:抓取网站的相关配置,包括编码、抓取间隔、重试次数等
	// site设置详细参考http://webmagic.io/docs/zh/posts/ch4-basic-page-processor/spider-config.html
	// setCharset -- 编码
	// setSleepTime -- 休眠时间 单位毫秒
	// setCycleRetryTimes -- 设置循环重试次数
	// 其中循环重试cycleRetry是0.3.0版本加入的机制。该机制会将下载失败的url重新放入队列尾部重试,直到达到重试次数,以保证不因为某些网络原因漏抓页面。
	private Site site = Site.me().setCharset("utf-8").setSleepTime(1000).setCycleRetryTimes(3);

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

	// process是定制爬虫逻辑的核心接口,在这里编写抽取逻辑
	@Override
	public void process(Page page) {
		// 获取当前页url
		String url = page.getUrl().toString();
		String title = page.getHtml().xpath("/html/head/title/text()").toString();
		// 判断url是否符合规则
		if (url.matches(CSDN_HOMEPAGE) || url.matches(CSDN_URL_REGEXP)||url.matches(CSDN_HOMEPAGE_REGEXP)) {
			// 判断url类型
			// 1.如果是首页,则获取游戏制作和数据库分类
			if (url.equals(CSDN_HOMEPAGE)) {
				// 获取数据库
				String dbString = page.getHtml().xpath("//div[@class='nav_com']/ul/li[8]/a/@href").toString();
				// 游戏开发
				String gameDevString = page.getHtml().xpath("//div[@class='nav_com']/ul/li[10]/a/@href").toString();
				// https://www.csdn.net/nav/db
				// 手动拼接完整的url
				dbString = CSDN_HOMEPAGE + dbString.substring(1);
				gameDevString = CSDN_HOMEPAGE + gameDevString.substring(1);
				List<String> list = new ArrayList<String>();
				list.add(gameDevString);
				list.add(dbString);
				page.addTargetRequests(list);
			}
			
			// 2. 如果是数据库页面或者游戏开发页面
			if (url.equalsIgnoreCase(CSDN_DB) || url.equalsIgnoreCase(CSDN_GAME)) {
				 List<String> listDBGAME = page.getHtml().xpath("//div[@class='title']/h2/a/@href").all();
				 page.addTargetRequests(listDBGAME);
			}
			
			// 3. 如果是文章的页面,例如:https://blog.csdn.net/xx5533/article/details/81773265,则爬/存储标题,且爬所有的url
			if(url.matches(CSDN_ARTICLE)) {
				String artTitle = page.getHtml().xpath("//h1[@class='title-article']/text()").toString();
				map.put(artTitle, url);
				List<String> artList = page.getHtml().links().regex(CSDN_URL_REGEXP).all();
				page.addTargetRequests(artList);
				page.putField(artTitle,url);
			}
			
		} else { // 不符合首页和博客,则存储起来。
			otherUrlMap.put(title, url);
		}
	}

	public static void main(String[] args) {
		System.out.println("爬虫开始--------------------");
		Spider.create(new CsdnProcessor())
			.addUrl(CSDN_HOMEPAGE)
            // url去重,需指定路径,会建立.urls.txt和.cursor.txt两个文件
            // 这里属于Scheduler,scheduler官网http://webmagic.io/docs/zh/posts/ch6-custom-componenet/scheduler.html
			.setScheduler(new FileCacheQueueScheduler("/home/mozhipeng/下载/1/").setDuplicateRemover(new BloomFilterDuplicateRemover(10000)))
			// 控制台打印
			.addPipeline(new CsdnConsolePipeline())
			// 文件下载
			//.addPipeline(new CsdnFilePipeline())
			.thread(2)
			.run();
		System.out.println("爬虫结束---------------------");
	}

}

Scheduler是WebMagic中进行URL管理的组件。一般来说,Scheduler包括两个作用:

  1. 对待抓取的URL队列进行管理。
  2. 对已抓取的URL进行去重。

WebMagic内置了几个常用的Scheduler。如果你只是在本地执行规模比较小的爬虫,那么基本无需定制Scheduler,但是了解一下已经提供的几个Scheduler还是有意义的。

说明备注
DuplicateRemovedScheduler抽象基类,提供一些模板方法继承它可以实现自己的功能
QueueScheduler使用内存队列保存待抓取URL 
PriorityScheduler使用带有优先级的内存队列保存待抓取URL耗费内存较QueueScheduler更大,但是当设置了request.priority之后,只能使用PriorityScheduler才可使优先级生效
FileCacheQueueScheduler使用文件保存抓取URL,可以在关闭程序并下次启动时,从之前抓取到的URL继续抓取需指定路径,会建立.urls.txt和.cursor.txt两个文件
RedisScheduler使用Redis保存抓取队列,可进行多台机器同时合作抓取需要安装并启动redis

在0.5.1版本里,我对Scheduler的内部实现进行了重构,去重部分被单独抽象成了一个接口:DuplicateRemover,从而可以为同一个Scheduler选择不同的去重方式,以适应不同的需要,目前提供了两种去重方式。

说明
HashSetDuplicateRemover使用HashSet来进行去重,占用内存较大
BloomFilterDuplicateRemover使用BloomFilter来进行去重,占用内存较小,但是可能漏抓页面

所有默认的Scheduler都使用HashSetDuplicateRemover来进行去重,(除开RedisScheduler是使用Redis的set进行去重)。如果你的URL较多,使用HashSetDuplicateRemover会比较占用内存,所以也可以尝试以下BloomFilterDuplicateRemover1,使用方式:

spider.setScheduler(new QueueScheduler()
.setDuplicateRemover(new BloomFilterDuplicateRemover(10000000)) //10000000是估计的页面数量
)
1. 0.6.0版本后,如果使用BloomFilterDuplicateRemover,需要单独引入Guava依赖包。  ↩

 

3. pipeline

3.1 

package com.mzp.csdn.spider.pipeline;

import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;

/**
 * @brief Pileline是抽取结束后,进行处理的部分,它主要用于抽取结果的保存,也可以定制Pileline可以实现一些通用的功能。  
 * @author: mozhipeng
 * @date:   2018年9月25日 上午9:18:29   
 * @note:
 */
public interface CsdnPipeline extends Pipeline{
	public void process(ResultItems resultItems,Task task);
}

3.2 控制台输出

package com.mzp.csdn.spider.pipeline.impl;

import java.util.Map;

import com.mzp.csdn.spider.pipeline.CsdnPipeline;

import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;

public class CsdnConsolePipeline implements CsdnPipeline {

	@Override
	public void process(ResultItems resultItems, Task task) {
		System.out.println("get page: " + resultItems.getRequest().getUrl());
		// 遍历所有结果,输出到控制台,上面例子中的"author"、"name"、"readme"都是一个key,其结果则是对应的value
		for (Map.Entry<String, Object> entry : resultItems.getAll().entrySet()) {
			System.out.println(entry.getKey() + ":\t测试=====>" + entry.getValue());
		}
	}

}

3.3 文件输出

package com.mzp.csdn.spider.pipeline.impl;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Map;

import org.apache.commons.codec.digest.DigestUtils;

import com.mzp.csdn.spider.pipeline.CsdnPipeline;

import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.FilePipeline;

public class CsdnFilePipeline extends FilePipeline implements CsdnPipeline {

	public CsdnFilePipeline() {
		setPath("/home/mozhipeng/下载/1");
	}

	public CsdnFilePipeline(String path) {
		setPath(path);
	}

	@Override
	public void process(ResultItems resultItems, Task task) {
		String path = this.path + PATH_SEPERATOR + task.getUUID() + PATH_SEPERATOR;
		try {
			PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(
					new FileOutputStream(getFile(path + resultItems.getRequest().getUrl().toString() + ".html")),
					"UTF-8"));
			printWriter.println("url:\t" + resultItems.getRequest().getUrl());
			for (Map.Entry<String, Object> entry : resultItems.getAll().entrySet()) {
				if (entry.getValue() instanceof Iterable) {
					Iterable value = (Iterable) entry.getValue();
					printWriter.println(entry.getKey() + ":");
					for (Object o : value) {
						printWriter.println(o);
					}
				} else {
					printWriter.println(entry.getKey() + ":\t" + entry.getValue());
				}
			}
			printWriter.close();
		} catch (IOException e) {

		}
	}

}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值