背景:女票快毕业了(没错!我是有女票的!!!),写论文,主题是儿童性教育,查看儿童性教育绘本数据死活找不到,没办法,就去当当网查询下数据,但是数据怎么弄下来呢,首先想到用Python,但是不会!!百度一番,最终决定还是用java大法爬虫,毕竟java熟悉点,话不多说,开工!:

  实现:

  首先搭建框架,创建一个maven项目,使用框架是springboot和mybatis,开发工具是idea,pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.com.boco</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.45</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

目录结构如下:

连接的数据库是oracle本地的数据库,配置文件如下

注意:application.yml文件中

spring:
profiles:
active:dev
指定的就是application_dev.yml文件,就是配置文件用的这个,在实际开发中,可以通过这种方式配置几份配置环境,这样发布的时候切换active属性就行,不用修改配置文件了

application_dev.yml配置文件:

server:
port: 8084 spring:
datasource:
username: system
password: 123456
url: jdbc:oracle:thin:@localhost
driver-class-name: oracle.jdbc.driver.OracleDriver mybatis:
mapper-locations: classpath*:mapping/*.xml
type-aliases-package: cn.com.boco.demo.entity #showSql
logging:
level:
com:
example:
mapper : debug

application.yml文件:

spring:
profiles:
active: dev

启动类如下,加上MapperScan注解,扫描dao层的接口:

@MapperScan("cn.com.boco.demo.mapper")
@SpringBootApplication
public class DemoApplication { public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
} }

dao层接口:

@Repository
public interface BookMapper { void insertBatch(List<DangBook> list); }

xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.com.boco.demo.mapper.BookMapper"> <insert id="insertBatch" parameterType="java.util.List">
INSERT ALL
<foreach collection="list" item="item" index="index" separator=" ">
into dangdang_message (title,img,author,publish,detail,price,parentUrl,inputTime) values
(#{item.title,jdbcType=VARCHAR},
#{item.img,jdbcType=VARCHAR},
#{item.author,jdbcType=VARCHAR},
#{item.publish,jdbcType=VARCHAR},
#{item.detail,jdbcType=VARCHAR},
#{item.price,jdbcType=DOUBLE},
#{item.parentUrl,jdbcType=VARCHAR},
#{item.inputTime,jdbcType=DATE}) </foreach>
select 1 from dual
</insert> </mapper>

两个实体类:

public class BaseModel {

    private int id;
private Date inputTime; public Date getInputTime() {
return inputTime;
} public void setInputTime(Date inputTime) {
this.inputTime = inputTime;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
}
}
@Alias("dangBook")
public class DangBook extends BaseModel { //标题
private String title;
//图片地址
private String img;
//作者
private String author;
//出版社
private String publish;
//详细说明
private String detail;
//价格
private float price;
//父链接,即请求链接
private String parentUrl; public String getParentUrl() {
return parentUrl;
} public void setParentUrl(String parentUrl) {
this.parentUrl = parentUrl;
} public String getAuthor() {
return author;
} public void setAuthor(String author) {
this.author = author;
} public String getPublish() {
return publish;
} public void setPublish(String publish) {
this.publish = publish;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public String getImg() {
return img;
} public void setImg(String img) {
this.img = img;
} public String getDetail() {
return detail;
} public void setDetail(String detail) {
this.detail = detail;
} public float getPrice() {
return price;
} public void setPrice(float price) {
this.price = price;
} }

service层:

@Service
public class BookService { @Autowired
private BookMapper bookMapper; public void insertBatch(List<DangBook> list){
bookMapper.insertBatch(list);
} }

controll层代码:

@RestController
@RequestMapping("/book")
public class DangdangBookController { @Autowired
private BookService bookService; private static Logger logger = LoggerFactory.getLogger(DemoApplication.class);
//url解码之后
private static final String URL = "http://search.dangdang.com/?key=性教育绘本&act=input&att=1000006:226&page_index=";
//url解码之前
private static final String URL2 = "http://search.dangdang.com/?key=%D0%D4%BD%CC%D3%FD%BB%E6%B1%BE&act=input&att=1000006%3A226&page_index=";
@RequestMapping("/parse")
public JSONObject parse(){
JSONObject jsonObject = new JSONObject();
for(int i =1;i<=10;i++){
List<DangBook> dangBooks = ParseUtils.dingParse(URL+i);
if(dangBooks != null && dangBooks.size() >0){ logger.info("解析完数据,准备入库");
bookService.insertBatch(dangBooks);
logger.info("入库完成,入库数据条数"+ dangBooks.size());
jsonObject.put("code",1);
jsonObject.put("result","success");
}else{
jsonObject.put("code",0);
jsonObject.put("result","fail");
} }
return jsonObject;
} }

本来是前端传入地址解析的,但是发现参数丢失了,用url编码也不行,最后放到后台了

ParseUtils和HttpGetUtils工具类:
public class HttpGetUtils {

    private static Logger logger = LoggerFactory.getLogger(HttpGetUtils.class);

    public static String getUrlContent(String url) {
if (url == null) {
logger.info("url地址为空");
return null;
}
logger.info("url为:" + url);
logger.info("开始解析");
String contentLine = null;
//最新版httpclient.jar已经舍弃new DefaultHttpClient()
//但是还是可以用的
HttpClient httpClient = new DefaultHttpClient();
HttpResponse httpResponse = getResp(httpClient, url);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
try {
contentLine = EntityUtils.toString(httpResponse.getEntity(), "utf-8");
} catch (IOException e) {
e.printStackTrace();
}
}
logger.info("解析结束");
return contentLine;
} /**
* 根据url 获取response对象
*/
public static HttpResponse getResp(HttpClient httpClient, String url) {
logger.info("开始获取response对象");
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
try {
httpResponse = httpClient.execute(httpGet);
} catch (IOException e) {
e.printStackTrace();
}
logger.info("获取对象结束");
return httpResponse;
} }
public class ParseUtils {

    private static Logger logger = LoggerFactory.getLogger(ParseUtils.class);

    public static List<DangBook> dingParse(String url) {
List<DangBook> list = new ArrayList<>();
Date date = new Date();
if (url == null) {
logger.info("url为空,数据获取结束");
return null;
} logger.info("开始获取数据");
String content = HttpGetUtils.getUrlContent(url);
if (content != null)
logger.info("得到解析数据");
else {
logger.info("解析数据为空,数据获取结束");
return null;
} Document document = Jsoup.parse(content);
//遍历当当图书列表
for(int i =1;i<=60;i++){
Elements elements = document.select("ul[class=bigimg]").select("li[class=line"+i+"]");
for (Element e : elements) {
String title = e.select("p[class=name]").select("a").text();
logger.info("书名:" + title);
String img = e.select("a[class=pic]").select("img").attr("data-original");
logger.info("图片地址:" + img);
String authorAndPublish = e.select("p[class=search_book_author]").select("span").select("a").text();
String []a = authorAndPublish.split(" ");
String author = a[0];
logger.info("作者:" + author);
String publish = a[a.length - 1];
logger.info("出版社:" + publish);
// String publish =e.select("p[class=name]").select("a").text();
String detail = e.select("p[class=detail]").text();
logger.info("图书介绍:" + detail);
String priceS = e.select("p[class=price]").select("span[class=search_now_price]").text();
float price = 0.0f;
if(priceS.length()>1 && priceS != null){
price = Float.parseFloat(priceS.substring(1, priceS.length() - 1));
}
logger.info("价格:" + price);
logger.info("-------------------------------------------------------------------------");
DangBook dangBook = new DangBook();
dangBook.setTitle(title);
dangBook.setImg(img);
dangBook.setAuthor(author);
dangBook.setPublish(publish);
dangBook.setDetail(detail);
dangBook.setPrice(price);
dangBook.setParentUrl(url);
dangBook.setInputTime(date);
list.add(dangBook);
}
}
return list;
} }

最后表里数据如下:

注意:建表的时候注意字段类型,orcale的var(255)不够我的这个数据标题用,开始报错,后来改了字段类型,还有注意ID的自增和入库时间的自动添加,个人数据库较差,百度一番才弄好

【转】java爬虫,爬取当当网数据的更多相关文章

  1. java爬虫,爬取当当网数据

     背景:女票快毕业了(没错!我是有女票的!!!),写论文,主题是儿童性教育,查看儿童性教育绘本数据死活找不到,没办法,就去当当网查询下数据,但是数据怎么弄下来呢,首先想到用Python,但是不会!!百 ...

  2. python爬虫爬取赶集网数据

    一.创建项目 scrapy startproject putu 二.创建spider文件 scrapy genspider  patubole patubole.com   三.利用chrome浏览器 ...

  3. 网络爬虫之定向爬虫:爬取当当网2015年图书销售排行榜信息(Crawler)

    做了个爬虫,爬取当当网--2015年图书销售排行榜 TOP500 爬取的基本思想是:通过浏览网页,列出你所想要获取的信息,然后通过浏览网页的源码和检查(这里用的是chrome)来获相关信息的节点,最后 ...

  4. Scrapy爬虫(5)爬取当当网图书畅销榜

      本次将会使用Scrapy来爬取当当网的图书畅销榜,其网页截图如下:   我们的爬虫将会把每本书的排名,书名,作者,出版社,价格以及评论数爬取出来,并保存为csv格式的文件.项目的具体创建就不再多讲 ...

  5. python爬虫06 | 你的第一个爬虫,爬取当当网 Top 500 本五星好评书籍

    来啦,老弟 我们已经知道怎么使用 Requests 进行各种请求骚操作 也知道了对服务器返回的数据如何使用 正则表达式 来过滤我们想要的内容 ... 那么接下来 我们就使用 requests 和 re ...

  6. python爬取当当网的书籍信息并保存到csv文件

    python爬取当当网的书籍信息并保存到csv文件 依赖的库: requests #用来获取页面内容 BeautifulSoup #opython3不能安装BeautifulSoup,但可以安装Bea ...

  7. Python爬虫爬取全书网小说,程序源码+程序详细分析

    Python爬虫爬取全书网小说教程 第一步:打开谷歌浏览器,搜索全书网,然后再点击你想下载的小说,进入图一页面后点击F12选择Network,如果没有内容按F5刷新一下 点击Network之后出现如下 ...

  8. Java实现爬取京东手机数据

    Java实现爬取京东手机数据 最近看了某马的Java爬虫视频,看完后自己上手操作了下,基本达到了爬数据的要求,HTML页面源码也刚好复习了下,之前发布两篇关于简单爬虫的文章,也刚好用得上.项目没什么太 ...

  9. scrapy项目3:爬取当当网中机器学习的数据及价格(spider类)

    1.网页解析 当当网中,人工智能数据的首页url如下为http://category.dangdang.com/cp01.54.12.00.00.00.html 点击下方的链接,一次观察各个页面的ur ...

随机推荐

  1. CQRS(Command and Query Responsibility Segregation)与EventSources实例

    CQRS The CQRS pattern and event sourcing are not mere simplistic solutions to the problems associate ...

  2. 8. java 面向对象

    一.面向对象特征 1. 封装 方法就是一种封装 关键字private也是一种封装 封装就是讲一些逻辑细节信息隐藏起来,对于外界不可见:外界只需调用我即可: 一旦使用了private进行修饰,那么本类当 ...

  3. 浅谈浏览器解析 URL+DNS 域名解析+TCP 三次握手与四次挥手+浏览器渲染页面

    (1)浏览器解析 URL 为了能让我们的知识层面看起来更有深度,我们应该考虑下面两个问题了: 从浏览器输入 URL 到渲染成功的过程中,究竟发生了什么? 浏览器渲染过程中,发生了什么,是不是也有重绘与 ...

  4. vmware workstations 虚拟机安装CentOS

    1.下载vmware ,我的版本是从上学时保存网盘的,版本比较低,链接如下: 链接:https://pan.baidu.com/s/19QP0q8xmPWIPn-rziPTvKg 提取码:lvh9 2 ...

  5. cookie和session及token的区别联系

    1 发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新的HTTP协议, 就是请求加响应,  尤其是我 ...

  6. 【STM32H7教程】第21章 STM32H7的NVIC中断分组和配置(重要)

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第21章       STM32H7的NVIC中断分组和配置( ...

  7. 10-scrapy框架介绍

    Scrapy 入门教程 Scrapy 是用 Python 实现的一个为了爬取网站数据.提取结构性数据而编写的应用框架. Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中. 通 ...

  8. Ansible之roles角色

    一.roles简介 ansible自1.2版本引入的新特性,用于层次性.结构化地组织playbook.roles能够根据层次型结构自动装载变量文件.tasks以及handlers等.要使用roles只 ...

  9. Promise如何解决回调地狱

    为什么要有promise:解决(回调地狱)的问题 ### 回调地狱: ```js //跟以前的if条件地狱很像 // if(){ // if(){ // if(){ // } // } //} $.g ...

  10. java高并发系列 - 第8天:线程组

    线程组 我们可以把线程归属到某个线程组中,线程组可以包含多个线程以及线程组,线程和线程组组成了父子关系,是个树形结构,如下图: 使用线程组可以方便管理线程,线程组提供了一些方法方便方便我们管理线程. ...