陈天平--第二次作业


这个作业属于哪个课程 至诚软工实践F班
这个作业要求在哪里 第二次作业-个人编程
这个作业的目标 数据、接口抓取;版本控制
Github 地址 GitHub地址

part01

使用 fiddler 抓包工具+代码,实时监控朴朴上某产品的详细价格信息。

思考

  • 爬取数据,需要接口,获取接口使用fiddler,拿到接口,编写程序,

步骤

  • 抓取接口

准备: 安装并配置fiddler

开始:

测试接口:

分析数据:

在线解析json

  • 编写程序

    准备:开发平台 idea,语言:Java (api),jdk版本 1.8

    开始:

    • 获取响应目标商品数据:需要发送一个请求来获取响应的内容

      Utils的sendGet()实现了这一需求

      注释掉的是原始请求头的内容(微信小程序)

      /**
           * 功能:发送GET请求,获取响应体
           * @param _url 请求URL
           * @return 响应体
           */
          public String sendGet(String _url) throws IOException {
              URL url = new URL(_url);
              HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      //        connection.setRequestProperty("Host","j1.pupuapi.com");
      //        connection.setRequestProperty("Connection","keep-alive");
      //        connection.setRequestProperty("Accept","application/json");
              connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat");
      //        connection.setRequestProperty("content-type","application/json");
      //        connection.setRequestProperty("open-id","oMwzt0HELosalSPJfmKq2cifPTAk");
      //        connection.setRequestProperty("pp-os","0");
      //        connection.setRequestProperty("pp-placeid","227bd5f1-40d5-4bdf-b5c2-2e091a512c9d");
      //        connection.setRequestProperty("pp-version","2021063100");
      //        connection.setRequestProperty("pp_storeid","7c1208da-907a-4391-9901-35a60096a3f9");
      //        connection.setRequestProperty("Referer","https://servicewechat.com/wx122ef876a7132eb4/156/page-frame.html");
      //        connection.setRequestProperty("Accept-Encoding","gzip, deflate, br");
      //        connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9,en;q=0.8");
              connection.connect();
              BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
              StringBuilder result = new StringBuilder();
              String lines;
              while ((lines = reader.readLine()) != null) {
                  lines = new String(lines.getBytes(), StandardCharsets.UTF_8);
                  result.append(lines).append("\n");
              }
              reader.close();
              connection.disconnect();
              return result.toString();
          }
      

      注意】如果放开以下代码,控制台输出乱码(请求编码问题)

      // connection.setRequestProperty("Accept-Encoding","gzip, deflate, br");

    • 数据处理

      响应信息

      JSONObject.parseObject(new Utils().sendGet(url));
      

      商品JSON数据

      JSONObject data = jsonObject.getJSONObject("data");
      

      商品名

      data.get("name")
      

      折后价

      data.get("price")
      

      原价

      data.get("market_price")
      

      Main 主类

      getGoodsData概要

      /**
       * 功能:获取商品信息
       * @param url 商品地址
       * @return 返回商品信息
       * */
      public String getGoodsData(String url) throws IOException {
          StringBuilder sb = new StringBuilder();
          Main main = new Main();
          // 数据转json格式
          JSONObject jsonObject = JSONObject.parseObject(new Utils().sendGet(url));
          // 得到data部分
          JSONObject data1 = jsonObject.getJSONObject("data");
          // 添加关键信息 到 sb
      	...
          sb.append("价格:").append(main.stringToDouble(data1.get("price").toString())).append("\n");
          ...
          return sb.toString();
      }
      

      getPrice 返回的数据中,商品的价格是实际的100倍(即没有小数),展示时需要转换成小数

      /**
           * 功能:获取商品价格
           * @param priceStr 目标商品的数据字符串
           * @return 双精度商品价格
           * */
      public double getPrice(String priceStr){
          // 转json 并 得到data部分
          return Double.parseDouble(JSONObject.parseObject(priceStr).getJSONObject("data").get("price").toString())/100;
      }
      

      实时查看价格实现

      线程在后台线程中调度,设置为定期重复执行。(注意访问太频繁会被封ip)

      /**
       * 功能:展示价格波动
       * @param url 指定访问url
       * @param time 访问间隔时长(单位:秒)
       * */
      public void displayPrice(String url, int time){
          Timer timer = new Timer();
          // 定时任务
          timer.schedule(new TimerTask(){
              @Override
              public void run() {
                  try{
                      double price = new Main().getPrice(new Utils().sendGet(url));
                      System.out.println("当前时间为:" + getLocalTime() + ",价格为:" + price);
                  }catch (Exception e){
                      e.printStackTrace();
                  }
              }
          },0,time*1000);
      }
      

    ? 运行结果:

    ?

    ? 需要优化的地方:功能函数不输出信息等

    ? 该优化在第二次提交部分实现

  • 上传到GitHub仓库

  • GitHub截图

  • 遇到问题与解决方案

    csdn

part02

爬取自己的知乎收藏夹,以每个收藏夹的名称为大类,其下展示各个具体收藏文章的名称及其链接。

思考

  • 跟part01差不多,不同的就是处理数据和数据展示

步骤

  • 使用fidder得到的接口

    https://www.zhihu.com/api/v4/people/zhi-hu-yong-hu-2021-36/collections
    
  • 获取收藏夹id集合

    /**
     * 功能:获取收藏夹id
     * @param url 收藏夹
     * @return 收藏夹id列表
     * */
    public ArrayList getPackageId(String url) throws IOException {
        Utils utils = new Utils();
        JSONObject jsonObject = JSONObject.parseObject(utils.sendGet(url));
        JSONArray data = JSONArray.parseArray(jsonObject.get("data").toString());
        System.out.println("该用户共有" + data.size() + "个收藏夹");
        ArrayList arrayList = new ArrayList<>();// 收藏夹id  方便后续请求收藏夹下的文章
        for (Object datum : data) {
            // 转换
            JSONObject temp = JSONObject.parseObject(datum.toString());
            System.out.println("title: " + temp.get("title") + " , description: " + temp.get("description") + " , url: " + temp.get("url"));
            // 记录收藏夹id
            arrayList.add(temp.get("id").toString());
        }
        return arrayList;
    }
    
  • 输出所有收藏夹包含的文章信息

    /**
     * 功能:输出文章信息
     * @param packageId 收藏夹id列表
     * */
    public void displayData(ArrayList packageId) throws IOException {
        // 接口格式 https://www.zhihu.com/api/v4/collections/xxxxx/items?offset=0&limit=20  其中xxxxx为收藏夹id
        Utils utils = new Utils();
        System.out.println("----------------------------------------------------------------------------");
        for (Object id : packageId) {
            String _url = "https://www.zhihu.com/api/v4/collections/" + id + "/items?offset=0&limit=20";
            // 查看数据
            JSONObject object = JSONObject.parseObject(utils.sendGet(_url));
            JSONArray data1 = JSONObject.parseArray((object.get("data").toString()));// 单篇文章内容对象 每个对象5个Object
            for (Object o : data1) {
                JSONObject temp = JSONObject.parseObject(o.toString());
                JSONObject content = JSONObject.parseObject(temp.get("content").toString());// 单篇文章内容
                JSONObject question = JSONObject.parseObject(content.get("question").toString());// 问题对象
                String title = question.get("title").toString();// 问题
                String excerpt = content.get("excerpt").toString();// 回答
                String mk_content = content.get("content").toString();// Markdown格式问题,获取图片地址
                if (mk_content.indexOf("
  • 运行结果

sendGet等其他步骤与part01相似