2.阿里云 大数据开发实践odpscmd数据保存到本地和MySQL

点击 接上文 —— ——>

一.创建电影数据表

登录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();
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
阿⾥巴巴⼤数据之路 阿⾥巴巴⼤数据之路——数据技术篇 数据技术篇 ⼀、整体架构 ⼀、整体架构      从下⾄上依次分为数据采集层、数据计算层、数据服务层、数据应⽤层    数据采集层:以DataX为代表的数据同步⼯具和同步中⼼    数据计算层:以MaxComputer为代表的离线数据存储和计算平台    数据服务层:以RDS为代表的数据库服务(接⼝或者视图形式的数据服务)    数据应⽤层:包含流量分析平台等数据应⽤⼯具 ⼆、数据采集(离线数据同步) ⼆、数据采集(离线数据同步)   数据采集主要分为⽇志采集和数据库采集。⽇志采集暂略(参考书籍原⽂)。我们主要运⽤的是数据库采集(数据库同步)。   通常情况下,我们需要规定原业务系统表增加两个字段:创建时间、更新时间(或者⾄少⼀个字段:更新时间)   数据同步主要可以分为三⼤类:直连同步、数据⽂件同步、数据库⽇志解析同步   1.直连同步     通过规范好的接⼝和动态连接库的⽅式直接连接业务库,例如通过ODBC/JDBC进⾏直连     当然直接连接业务库的话会对业务库产⽣较⼤压⼒,如果有主备策略可以从备库进⾏抽取,此⽅式不适合直接从业务库到数仓的情景   2.数据⽂件同步     从源系统⽣成数据⽂本⽂件,利⽤FTP等传输⽅式传输⾄⽬标系统,完成数据的同步     为了防⽌丢包等情况,⼀般会附加⼀个校验⽂件 ,校验⽂件包含数据量、⽂件⼤⼩等信息     为了安全起见还可以加密压缩传输,到⽬标库再解压解密,提⾼安全性   3.数据库⽇志同步     主流数据库都⽀持⽇志⽂件进⾏数据恢复(⽇志信息丰富,格式稳定),例如Oracle的归档⽇志   (数据库相关⽇志介绍,参考:)    4.阿⾥数据仓库同步⽅式     1)批量数据同步     要实现各种各样数据源与数仓的数据同步,需要实现数据的统⼀,统⼀的⽅式是将所有数据类型都转化为中间状态,也就是字符串类型。以此来实现数据格式的统⼀。     产品——阿⾥DataX:多⽅向⾼⾃由度异构数据交换服务产品,产品解决的主要问题:实现跨平台的、跨数据库、不同系统之间的数据同步及交互。     产品简介:     开源地址:     更多的介绍将会通过新开随笔进⾏介绍!(当然还有其他主流的数据同步⼯具例如kettle等!)     2)实时数据同步     实时数据同步强调的是实时性,基本原理是通过数据库的⽇志(MySQL的bin-log,Oracle的归档⽇志等)实现数据的增量同步传输。     产品——阿⾥TimeTunnel(简称TT)。TT产品本质是⼀个⽣产者、消费者模型的消息中间件     3)常见问题       1.增量数据与全量数据的合并         主要的场景是数据同步中周期全量同步,对应的解决⽅案是每次只同步变更的数据,然后和上⼀周期合并,形成最新的全量数据(选择此⽅案的原因是绝⼤多 数⼤数据平台不⽀持update操作)         具体的⽅案主要有union的联合操作(可以通过⽣成增量中间表detal)与阿⾥主推的全外连接full outer join+全量覆盖insert overwrite的形式。实例参考如下: SQL的Join语法有很多, inner join(等值连接) 只返回两个表中联结字段相等的⾏, left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录, right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录, 假设我们有两张表。Table A 是左边的表。Table B 是右边的表。其各有四条记录,其中有两条记录name是相同的,如下所⽰: A表 id name 1 Pirate 2 Monkey 3 Ninja 4 Spaghetti B表 id name 1 Rutabaga 2 Pirate 3 Darth Vade 4 Ninja 让我们看看不同JOIN的不同。 FULL [OUTER] JOIN (1) SELECT * FROM TableA FULL OUTER JOIN TableB ON TableA.name = TableB.name TableA.name = TableB.name 的情况,A和B的交集有两条数据,那么 FULL OUTER JOIN的结果集, 应该是2+2+2=6条,即上⾯的交集,再加剩下的四条数据,没有匹配,以null补全。 结果集 (TableA.) (TableB.) id name id name 1 Pirate 2 Pirate 2 Monkey null null 3 Ninja 4 Ninja 4 Spaghetti null null null null 1 Rutabag
要将设备上传到阿里云物联网平台的数据导入到本地数据库中,可以按照以下步骤进行操作: 1. 首先,确保你的本地数据库已经设置好并且可以连接。常见的本地数据库MySQL、PostgreSQL、MongoDB等。 2. 在阿里云物联网平台中,找到数据导出或者数据集成的功能。这通常会在平台提供的数据管理或者设备管理模块中。 3. 配置数据导出的规则和方式。在物联网平台中,你可以选择使用数据导出功能将设备数据导出到本地。这通常涉及到配置导出的目标数据库、表格、字段映射等信息。 4. 在本地数据库中创建对应的表格结构。根据阿里云物联网平台导出的数据格式和字段映射,创建相应的表格和字段来存储数据。 5. 根据阿里云物联网平台提供的接口和文档,编写代码或配置相关工具来接收和处理导出的数据。这通常涉及到与阿里云物联网平台进行数据交互的API开发或集成。 6. 在代码中,使用适当的数据库连接库或者驱动来连接到本地数据库。根据数据库类型和编程语言的不同,你可以选择合适的库,如MySQL Connector、psycopg2、pymongo等。 7. 将从阿里云物联网平台导出的数据进行解析和格式转换,然后插入到本地数据库中。根据数据格式的不同,你可能需要使用JSON解析库或者其他数据转换工具来处理数据。 8. 针对不同的需求,你还可以在导入数据的过程中进行数据清洗、转换或其他处理操作,以确保数据的准确性和完整性。 需要注意的是,具体的步骤和工具可能会因阿里云物联网平台和数据库选择而有所不同。因此,建议参考相关平台和数据库的文档和开发指南来了解更详细的操作步骤和要点。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_胡杨_

感谢打赏,会多多更新的。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值