目录:
一.创建电影数据表
登录MySQL
mysql -u root -p
创建数据库clawler
create database clawler;
切换数据库
use clawler;
CREATE TABLE `film` (
`title` varchar(100) DEFAULT NULL,
`time` varchar(10) DEFAULT NULL,
`director` varchar(100) DEFAULT NULL,
`actor` varchar(100) DEFAULT NULL,
`amount` varchar(100) DEFAULT NULL,
`redate` date NOT NULL
) ;
desc film;
二.创建Java项目
创建3个Java项目用来抓取:
1.RetrivePage.java文件爬取网页和解析网页Java代码
package com.aliyun.odps.crawler;
import java.io.*;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.jsoup.nodes.Element;
import java.io.FileWriter;
import java.io.FileOutputStream;
//类名
public class RetrivePage {
//从指定URL解析网页内容;@param path 需要解析网页的URL链接地址
public void analyzePage(String path) throws IOException{
// 实现包括向读取URL内容并进行解析的过程
// 1、读取网页(读取URL内容)
// 解析文件名,创建写入文件的名称
String filename = path.substring(path.lastIndexOf('/') + 1).substring(0, path.substring(path.lastIndexOf('/') + 1).length() -5);
// 创建字符输出流类对象和已存在的文件相关联,若文件不存在,并创建。
FileWriter fileWriter = new FileWriter(filename + ".txt");
// 读取网页
Document document = Jsoup.connect(path).get();
// 2、解析网页内容
// 获取电影名称
String movieTitle = document.getElementById("movieTitle").text();
fileWriter.write("movieTitle:" + movieTitle);
fileWriter.write("\r\n");
fileWriter.write("***************************\r\n");
// 获取电影相关信息
String info = document.getElementById("info").text();
fileWriter.write(info);
fileWriter.write(info);
fileWriter.write("\r\n");
fileWriter.write("***************************\r\n");
// 获取电影评分
String score = document.getElementById("rating_num").text();
fileWriter.write("score:" + score);
fileWriter.write("\r\n");
fileWriter.write("***************************\r\n");
//获取电影评分
Elements container = document.getElementsByClass("article");
Document containerDoc = Jsoup.parse(container.toString());
Element comment = containerDoc.getElementById("comments-section");
Document commentDoc = Jsoup.parse(comment.toString());
Elements cmtslist = commentDoc.getElementsByClass("comment-item");
for (Element clearfix : cmtslist){
// 获取评论人
String discussant = clearfix.getElementsByClass("comment-info").text();
fileWriter.write("discussant:" + discussant);
fileWriter.write("\r\n");
// 获取评论时间
String time = clearfix.getElementsByClass("comment-time").text();
fileWriter.write("comment-time:" + time);
fileWriter.write("\r\n");
// 获取评论内容
String commentContent = clearfix.select("p").get(0).text();
fileWriter.write("comment-content:" + commentContent);
fileWriter.write("\r\n");
fileWriter.write("====================================\r\n");
}
// 刷新该流中的缓存。将缓冲区中的字符数据保存到目的文件夹中去。
fileWriter.flush();;
// 关闭此流
fileWriter.close();
}
//从指定URL下载网页内容;@param path 需要抓取网页的URL链接地址;@return 抓取网页内容成功返回true,否则返回false
public boolean downloadPage(String path) throws HttpException, IOException {
// 包括向URL提交请求、处理网页数据的返回流两个过程
// 1、向URL提交请求
// 创建HttpClient对象
HttpClient httpClient = new HttpClient();
InputStream inputStream = null;
OutputStream outputStream = null;
// 得到get方法
GetMethod getMethod = new GetMethod(path);
// 执行,返回状态码
int statusCode = httpClient.executeMethod(getMethod);
System.out.println("状态码:" + statusCode);
// 2、处理网页数据的返回流
// 针对状态码进行处理(只处理返回值为200的状态码)
if (statusCode == HttpStatus.SC_OK) {
inputStream = getMethod.getResponseBodyAsStream();
// 得到文件名
String filename = path.substring(path.lastIndexOf('/') + 1);
System.out.println("文件名:" + filename);
// 获得文件输出流
outputStream = new FileOutputStream(filename);
// 输出到文件
int tempByte = -1;
while ((tempByte = inputStream.read()) > 0) {
outputStream.write(tempByte);
}
// 关闭输入输出流
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
return true;
}
return false;
}
//抓取并解析指定URL的网页内容类;@param args
public static void main(String[] args) {
RetrivePage retrivePage = new RetrivePage();
try {
// 以http://www.datawh.cn/fast8.html网站为例
String path = "http://www.datawh.cn/fast8.html";
retrivePage.downloadPage(path);
retrivePage.analyzePage(path);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.CrawlDatatoBase.Java文件爬取网页保存到本地和MySQL数据库
package com.aliyun.odps.crawler;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
//数据库存储类
public class CrawlDatatoBase {
static Connection conn;
static Statement st;
//主方法测试数据库连接* @param args*/
public static void main(String[] args) {
setConn();
}
//将数据插入数据库
public static boolean InsertProduct(ArrayList<String> datalist) {
try {
// 获取当前日期
Date now = new Date();
// 通过指定格式实例化日期转化为字符串模板
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
// 用模板将Date类型日期格式化成字符串
String redate = dateFormat.format(now);
// 将日期加入datalist集合
datalist.add(redate);
// 定义将执行插入操作的insql语句
String insql = "INSERT INTO film(title,time,director,actor,amount,redate) VALUES(?,?,?,?,?,?)";
// 实例化PreparedStatement对象,预处理insql语句
PreparedStatement ps = conn.prepareStatement(insql);
int i;
for (i = 0; i < datalist.size(); i++) {
// 获取datalist集合中的每一条数据
String strvalue = datalist.get(i);
// 循环取得datalist中的数据并设置进VALUES中的?里面
ps.setString(i + 1, strvalue);
}
// 执行insql语句,若成功,则返回一个正数,否则返回0
int result = ps.executeUpdate();
// 关闭PreparedStatement对象
ps.close();
// result大于0说明插入操作成功
if (result > 0) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
//调用getConnection方法连接数据库,增加安全性
public static void setConn() {
conn = getConnection();
}
//关闭数据库连接
public static void closeConn() {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection con = null;
// 定义驱动类必须有驱动包,例如:mysql-connector-java-5.1.27.jar
String DBDRIVER = "com.mysql.jdbc.Driver";
// 定义用户名
String DBUSER = "root";
// 定义数据库密码
String DBPASS = "1";
// 定义url IP 数据库名字
String DBURL = "jdbc:mysql://192.168.230.129:3306/clawler";
try {
// 加载数据库驱动类
Class.forName(DBDRIVER);
// 连接数据库
con = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
System.out.println("数据库连接成功...");
} catch (Exception e) {
// 如果连接失败,获取失败的信息
System.out.println("数据库连接失败" + e.getMessage());
}
return con;
}
}
3.CrawlPage.Java实现爬取逻辑
package com.aliyun.odps.crawler;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
//爬取类名
public class CrawlPage {
// 创建一个客户端
private static CloseableHttpClient httpclient = HttpClients.createDefault();
// 注意:定义输出html文件的路径 记得改自己的路径
private static String filename = "D:\\IDEA\\代码保存\\项目二MySQL" + File.separator + File.separator + "film.html";
// 注意:定义输出csv文件的路径 记得改自己的路径
private static String outfile = "D:\\IDEA\\代码保存\\项目二MySQL" + File.separator + File.separator + "film.csv";
// 定义控制输出file的boolean变量
private static boolean bfile = true;
// 定义控制输出file的boolean变量
private static boolean bdb = true;
// 定义Arraylist类集用来保存每一条数据的信息
private static ArrayList<String> datalist = new ArrayList<String>();
// 打印的标题头
private static String headtitle = "电影名称,上映时间,导演,演员,评价人数";
// 计数变量
private static int countrs = 0;
//下载页面* @param url* @return* @throws Exception
public static String downloadPage(String url) throws Exception {
// 定义返回的String变量
String htmlString = "";
// 请求资源
HttpGet request = new HttpGet(url);
//表头
request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36");
// 得到回应
CloseableHttpResponse response = httpclient.execute(request);
try {
// 打印状态码
System.out.println(response.getStatusLine());
// 获得Entity对象
HttpEntity entity = response.getEntity();
// 将Entity对象转化为字符串
htmlString = EntityUtils.toString(entity);
// 销毁对象
EntityUtils.consume(entity);
} finally {
response.close();
}
// 调用htmltoFile()方法在制定路径输出html文件
htmltoFile(htmlString);
return htmlString;
}
//输出html文件* @param htmlString* @throws Exception
public static void htmltoFile(String htmlString) throws Exception {
// 获得文件输出流
FileOutputStream output = new FileOutputStream(filename);
// 以utf-8编码的形式输出到文件(utf-8是中文编码,ISO-8859-1是英文编码)
output.write(htmlString.getBytes("utf-8"));
if (output != null) {
output.close();
}
}
//获取所有豆瓣电影列表* @param surl* @throws Exception
public static void getDouBanList(String surl) throws Exception {
// 通过url下载页面
String html = CrawlPage.downloadPage(surl);
// 用"star_clearfix"替代"star clearfix"
html = html.replace("star clearfix", "star_clearfix");
// 解析获取Document对象
Document doc = Jsoup.parse(html);
// 通过getElementsByClass方法获取class为"grid_view"的div节点对象
Element divNode = doc.getElementsByClass("grid_view").first();
// 通过select选择器选择有class属性的li标签节点,返回Element元素的集合
Elements liTag = divNode.select("li[class]");
String title, time, director, actor, amount;
// 对于liTag Element集合中的每一个元素liNode
for (Element liNode : liTag) {
// 取得liNode的第一个dd节点对象
Element dd = liNode.select("dd").first();
// 使用getElementsByTag方法,通过标签名称取得a标签节点对象,然后取其中的文本元素,即为电影名称
title = dd.getElementsByTag("a").text();
// 添加每一条数据前先清空之前添加的内容(由于是循环添加,一定要清空前一次添加的内容)
datalist.clear();
// 将title(电影名称)添加进datalist集合
datalist.add(title);
// 选择dd节点里面的第一个h6节点对象
Element h6 = dd.select("h6").first();
// 进一步选择h6节点对象的第一个span节点对象
Element a = h6.select("span").first();
// 取得第一个span节点对象的文本内容,初步取出时间
time = a.text();
// 进一步处理文本内容,去掉左括号
time = time.replace("(", "");
// 进一步处理文本内容,去掉右括号
time = time.replace(")", "");
// 将time(上映时间)添加进datalist集合
datalist.add(time);
// 通过select选择器选择dd节点的第一个dl节点
Element dl = dd.select("dl").first();
// 通过select选择器选择dl节点的第一个dd节点
Element d1 = dl.select("dd").first();
// 因为有些电影导演数据可能为空,为空(null)时会出现异常,所以在这里进行处理,将null转化为"";
if (d1 != null) {
// 获取d1的文本对象即为导演
director = d1.text();
} else {
director = "";
}
// 将director(导演)添加进datalist集合
datalist.add(director);
// 通过select选择器选择dl节点的最后一个dd节点
Element d2 = dl.select("dd").last();
if (d2 != null) {
actor = d2.text();
} else {
actor = "";
}
datalist.add(actor);
// 通过getElementsByClass方法获取class为"star_clearfix"的节点对象
Element foot = liNode.getElementsByClass("star_clearfix").first();
// 通过select选择器选择foot的最后一个span对象
Element span = foot.select("span").last();
// 取得span里面的文本元素即为评论数量
amount = span.text();
datalist.add(amount);
// 调用outputRs方法将datalist里面的每一条数据插入到数据库
outputRs();
}
}
//*** 输出到数据库@throws Exception
private static void outputRs() throws Exception {
String strout = "";
for (int i = 0; i < datalist.size(); i++) {
// 获取datalist集合中的每一条数据,串成一个字符串
strout = strout + datalist.get(i) + ",";
}
if (bfile) {
// 实例化文件输出流
FileWriter fw = new FileWriter(outfile, true);
// 实例化打印流
PrintWriter out = new PrintWriter(fw);
if (countrs == 0)
// 输出头标题
out.println(headtitle);
// 输出刚刚串起来的strout字符串
out.println(strout);
// 关闭打印流
out.close();
// 关闭输出流
fw.close();
}
countrs = countrs + 1;
// 在命令行打印数据
System.out.println(countrs + " " + strout);
// 插入数据库
if (bdb) {
CrawlDatatoBase.InsertProduct(datalist);
}
}
//翻页爬取 @param surl* @throws Exception
public static void skipPage(String surl) throws Exception {
String html = CrawlPage.downloadPage(surl);
Document doc = Jsoup.parse(html);
// 获取页码部分的div对象
Element footDiv = doc.getElementsByClass("paginator").first();
// 获取class为"next"的节点对象用footSpan表示
Element footSpan = footDiv.getElementsByClass("next").first();
// 选择footSpan中第一个带有href属性的a节点对象,并用footA表示
Element footA = footSpan.select("a[href]").first();
// 获得footA中href属性中的内容href
String href = footA.attr("href");
//将"http://movie.douban.com/celebrity/1054424/movies"和href拼接即为下一页面的url
String http = "http://movie.douban.com/celebrity/1054424/movies" + href;
// 获取当前页码节点
Element thispage = doc.getElementsByClass("thispage").first();
// 获取当前页码中的数字元素(String类型),并转化为int类型
int end = Integer.parseInt(thispage.text());
if (end == 1) {
getDouBanList(surl);
System.out.println("==========================" + 1 + "===================");
}
// 爬取下一页面
try {
getDouBanList(http);
} catch (Exception e) {
e.printStackTrace();
}
// 打印一行页面分隔符
System.out.println("==========================" + (end + 1) + "===================");
// 由于一共是19页,所以end小于19的时候循环爬取
if (end < 19) {
skipPage(http);
} else {
System.out.println("页面已爬完");
}
}
//主方法* @param args
public static void main(String[] args) {
String strURL = "http://movie.douban.com/celebrity/1054424/movies?sortby=time&format=pic&&qq-pf-to=pcqq.group";
try {
CrawlDatatoBase.setConn();
// 翻页爬取
skipPage(strURL);
// 关闭数据库
CrawlDatatoBase.closeConn();
} catch (Exception e) {
e.printStackTrace();
}
}
}