欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實(shí)現(xiàn)網(wǎng)絡(luò)數(shù)據(jù)提取所需知識(shí)點(diǎn)

 更新時(shí)間:2020年07月31日 11:31:45   作者:sunwengang  
這篇文章主要介紹了Java實(shí)現(xiàn)網(wǎng)絡(luò)數(shù)據(jù)提取所需知識(shí)點(diǎn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

本篇對(duì)一些常用的java知識(shí)做一個(gè)整合,三大特性、IO操作、線程處理、類集處理,目的在于能用這些只是實(shí)現(xiàn)一個(gè)網(wǎng)頁(yè)爬蟲的功能。

Ⅰ    首先對(duì)于一個(gè)java開發(fā)的項(xiàng)目有一個(gè)整體性的了解認(rèn)知,項(xiàng)目開發(fā)流程:

項(xiàng)目階段:

1)項(xiàng)目準(zhǔn)備:

  a)根據(jù)開會(huì)得到會(huì)議紀(jì)要,了解客戶的需求情況

  b)需求分析(需求分析文檔)

  c)數(shù)據(jù)庫(kù)設(shè)計(jì)和網(wǎng)站(產(chǎn)品)原型設(shè)計(jì)

  d)架構(gòu)設(shè)計(jì)

2)項(xiàng)目開發(fā)

  a)項(xiàng)目組長(zhǎng)(PM,PL)進(jìn)行項(xiàng)目的時(shí)間規(guī)劃,并劃分好每個(gè)人的工作任務(wù)

  b)程序員主要完成項(xiàng)目代碼編寫和詳細(xì)設(shè)計(jì)文檔編寫。(用戶手冊(cè))

3)測(cè)試

  a)單元測(cè)試

  b)集成測(cè)試

  c)壓力測(cè)試

  d)回歸測(cè)試

4)上線實(shí)施

Ⅱ  三大特性(封裝、繼承、多態(tài))

封裝

1、  封裝重點(diǎn)在于一個(gè)private關(guān)鍵字,目的是為了讓類中的屬性不能直接修改或取得。也就是說,建立一個(gè)類時(shí),所有的屬性都必須通過private進(jìn)行封裝。

      既然屬性被封裝了,那么如果想設(shè)置或取得屬性,就必須編寫getter/setter方法。

      同時(shí),類中在創(chuàng)建對(duì)象時(shí),為了方便,一般建議編寫一些帶參數(shù)的構(gòu)造方法。

      如果不編寫構(gòu)造方法,程序會(huì)自動(dòng)加入一個(gè)無參的構(gòu)造,但是,如果自己聲明了構(gòu)造方法,那么必須就手工加入一個(gè)無參構(gòu)造,為了讓其他的框架可以通過無參數(shù)構(gòu)造來創(chuàng)建對(duì)象。

2、  如果數(shù)據(jù)庫(kù)中有一張表,則需要你能根據(jù)表編寫一個(gè)這樣的類。

      這種類被稱為:VO(Value Object)、TO(Transfer Object)、POJO(Plain Olds Java Object)、DTO(DaTa Object)等

class Person {
  private String name;
  private Integer age;
  public Person() {
  }
  public Person(String name, Integer age) {
    this.name = name;
    this.age = age;
  }
  public String getName() {
    return this.name;
  }
  public Integer getAge() {
    return age;
  }
  public void setAge(Integer age) {
    this.age = age;
  }
  public void setName(String name) {
    this.name = name;
  }
}

技巧:在eclipse中編寫封裝類,可以聲明變量后,按shift+Alt+s鍵出現(xiàn)Generate Getters and Setters提示創(chuàng)建getter和setter方法。

繼承關(guān)系

繼承所使用的關(guān)鍵字:extends,接口實(shí)現(xiàn)所使用的關(guān)鍵字是:implements。

Java開發(fā)中對(duì)于接口和抽象類區(qū)別主要是單繼承和多繼承。

真正開發(fā)中接口用的更多,幾乎不編寫抽象類。

一般都是以接口作為標(biāo)準(zhǔn)來進(jìn)行聲明。

這部分我們要求能夠掌握接口的聲明和實(shí)現(xiàn)方法。

interface Animal {
  public void cry();
  public void run();
}
class Cat implements Animal {

  @Override
  public void cry() {
    System.out.println("miao");
  }
  @Override
  public void run() {
    System.out.println("貓爬樹");
  }
}

多態(tài)

其實(shí)就是在繼承的基礎(chǔ)上進(jìn)行方法覆寫和子類轉(zhuǎn)型。

package org.liky.test;
public class InterfaceDemo {
  public static void main(String[] args) {
    Animal a1 = new Cat();
    Animal a2 = new Dog();
    a1.cry();
    a2.cry();
  }
}
interface Animal {
  public void cry();
  public void run();
}
class Cat implements Animal {
  @Override
  public void cry() {
    System.out.println("miao");
  }
  @Override
  public void run() {
    System.out.println("貓爬樹");
  }
}
class Dog implements Animal {
  @Override
  public void cry() {
    System.out.println("Wang");
  }
  @Override
  public void run() {
    System.out.println("狗游泳");
  }
}

單例設(shè)計(jì)模式

單例模式有以下特點(diǎn):

  1、單例類只能有一個(gè)實(shí)例。

  2、單例類必須自己創(chuàng)建自己的唯一實(shí)例。

  3、單例類必須給所有其他對(duì)象提供這一實(shí)例。

package org.liky.test;

public class TestSingleton {
  public static void main(String[] args) {
    Singleton s1 = Singleton.getInstance();
    Singleton s2 = Singleton.getInstance();
    Singleton s3 = Singleton.getInstance(); 
        //其實(shí)只創(chuàng)建了一個(gè)對(duì)象
     System.out.println(s1 + " --> " + s2 + " --> " + s3);    
  }
}
class Singleton {
  private static final Singleton instance = new Singleton();
  private Singleton() {
  }
  public static Singleton getInstance() {
    return instance;
  }
}

Ⅲ  IO操作

文件內(nèi)容讀?。?/p>

File、FileReader、FileWriter、BufferedReader、BufferedWriter、Scanner、InputStreamReader

文件夾遍歷:

File

文件復(fù)制操作

如果想操作文件的內(nèi)容(對(duì)內(nèi)容進(jìn)行寫出和讀?。?,需要使用到的就是IO流中的輸入輸出操作。

這種輸入和輸出的操作流有兩種:

1)字符流:主要操作文本文件(編寫爬蟲操作時(shí),肯定要使用字符流來完成)

a)讀:FileReader

b)寫:FileWriter

2)字節(jié)流:所有文件都可以使用這種流操作

a)讀:InputStream

b)寫:OutputStream

需要能夠通過我們這里的FileReader和FileWriter配合文件類:File,完成內(nèi)容的讀取和寫出。

/**
 * IO流操作的演示類,用來演示文本文件的寫出和讀取
 * 
 * @author Liky
 * 
 */
public class FileTest {
  public static void main(String[] args) {
    // 寫出內(nèi)容
    // writeData(
    // "D:/test.txt",
    // "這是“吉林一號(hào)”視頻衛(wèi)星 8月9日11時(shí)25分拍攝的 九寨溝縣視頻 顯示了九寨溝縣的地形地貌 縣城呈狹長(zhǎng)分布 周邊山體有明顯滑坡痕跡 視頻中還可見縣城道路大部分完好 有車輛通行 一架飛機(jī)飛過 地面與空中交通并未中斷 圖像提供:長(zhǎng)光衛(wèi)星技術(shù)有限公司 技術(shù)支持:北京愛太空科技發(fā)展有限公司");
    System.out.println(readData("D:/test.txt"));
  }

  /**
   * 寫出數(shù)據(jù)
   * 
   * @param filePath
   *      文件保存的位置
   * @param data
   *      要保存的文件內(nèi)容數(shù)據(jù)
   */
  public static void writeData(String filePath, String data) {
    // 先有一個(gè)文件,來保存要寫出的數(shù)據(jù)
    File file = new File(filePath);
    // 建立輸出流對(duì)象
    try {
      FileWriter writer = new FileWriter(file);
      // 開始完成內(nèi)容的輸出
      writer.write(data);
      // 資源必須回收,也就是必須將流關(guān)閉
      writer.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 讀取數(shù)據(jù)
   * 
   * @param filePath
   *      要讀取的文件所在的完整路徑
   * @return 讀取出來的文檔內(nèi)容
   */
  public static String readData(String filePath) {
    // 也要建立文件對(duì)象
    File file = new File(filePath);
    // 建立讀取的輸入流對(duì)象
    try {
      FileReader reader = new FileReader(file);

      // 每次調(diào)用read可以讀取一個(gè)字符,
      // 按照int類型返回,返回的是字符的編碼,
      // 需要通過強(qiáng)制類型轉(zhuǎn)換,變?yōu)閏har類型
      // Java中對(duì)于String這個(gè)類一般不建議反復(fù)修改,因?yàn)闀?huì)占用內(nèi)存。
      StringBuilder builder = new StringBuilder();
      // 因?yàn)槲募杏泻芏嗟淖址虼诵枰h(huán)來進(jìn)行內(nèi)容的讀取。
      // 就需要判斷是否還有字符進(jìn)行讀取
      int value = -1;
      // 每次讀取時(shí),如果讀到內(nèi)容,則會(huì)返回 0 - 65535 的char類型字符
      // 如果沒有讀取到內(nèi)容,則返回 -1 ,因此我們可以根據(jù)這個(gè) -1 來判斷后面是否還有內(nèi)容
      while ((value = reader.read()) != -1) {
        // 將讀取到的內(nèi)容保存下來
        char c = (char) value;
        // 把字符放入到StringBuilder里
        builder.append(c);
      }
      // 沒有讀取到內(nèi)容,說明循環(huán)結(jié)束,已經(jīng)到了文件的末尾
      return builder.toString();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }
}

目前這樣編寫已經(jīng)可以實(shí)現(xiàn)內(nèi)容的輸入和輸出操作了。

但是還不支持換行操作,如果想換行,需要人工進(jìn)行\(zhòng)r\n的編寫。

如果不想人工編寫換行,就可以使用以下兩個(gè)類來完成輸入。

PrintWriter(打印流)

BufferedWriter(緩沖流)

public static void writeData(String filePath, String... data) {
    // 先有一個(gè)文件,來保存要寫出的數(shù)據(jù)
    File file = new File(filePath);
    // 建立輸出流對(duì)象
    try {
      // FileWriter writer = new FileWriter(file);
      PrintWriter pw = new PrintWriter(file);
      // 開始完成內(nèi)容的輸出
      for (String str : data) {
        pw.println(str);
      }
      // 資源必須回收,也就是必須將流關(guān)閉
      pw.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

使用時(shí),注意我們這里加入了可變參數(shù)來動(dòng)態(tài)傳入多個(gè)字符串(即String... data)。

當(dāng)讀取數(shù)據(jù)時(shí),如果我們使用普通的讀取方式,對(duì)于換行的處理不方便。

如果想按行讀取內(nèi)容,可以使用BufferedReader,Scanner

Scanner是JDK1.5新的

BufferedReader是JDK1.0就有的,所以使用BufferedReader。

為什么現(xiàn)在還使用BufferedReader,因?yàn)镾canner不支持編碼的轉(zhuǎn)換。

public static String readData(String filePath) {
    // 也要建立文件對(duì)象
    File file = new File(filePath);
    // 建立讀取的輸入流對(duì)象
    try {
      FileReader reader = new FileReader(file);
      BufferedReader bw = new BufferedReader(reader);
      // 每次調(diào)用read可以讀取一個(gè)字符,
      // 按照int類型返回,返回的是字符的編碼,
      // 需要通過強(qiáng)制類型轉(zhuǎn)換,變?yōu)閏har類型
      // Java中對(duì)于String這個(gè)類一般不建議反復(fù)修改,因?yàn)闀?huì)占用內(nèi)存。
      StringBuilder builder = new StringBuilder();
      // 因?yàn)槲募杏泻芏嗟淖址?,因此需要循環(huán)來進(jìn)行內(nèi)容的讀取。
      // 就需要判斷是否還有字符進(jìn)行讀取
      String line = null;
      // 每次讀取時(shí),如果讀到內(nèi)容,則會(huì)返回 0 - 65535 的char類型字符
      // 如果沒有讀取到內(nèi)容,則返回 -1 ,因此我們可以根據(jù)這個(gè) -1 來判斷后面是否還有內(nèi)容
      while ((line = bw.readLine()) != null) {
        // 將讀取到的內(nèi)容保存下來
        // 把字符放入到StringBuilder里
        builder.append(line);
        System.out.println(line);
      }
      // 沒有讀取到內(nèi)容,說明循環(huán)結(jié)束,已經(jīng)到了文件的末尾
      return builder.toString();
    } catch (Exception e) {
      e.printStackTrace();
    }

    return null;
  }

例如,將一個(gè)D盤的test.txt的內(nèi)容讀取出來,再寫出到E盤的test.txt中

public static void copyFile(String inputFile, String outputPath) {
    // 首先建立輸入和輸出的文件
    File input = new File(inputFile);
    File output = new File(outputPath);
    // 建立輸入和輸出流
    try {
      BufferedReader br = new BufferedReader(new FileReader(input));
      PrintWriter pw = new PrintWriter(output);
      // 每次讀入一行,所以準(zhǔn)備一個(gè)變量來接收
      String line = null;
      while ((line = br.readLine()) != null) {
        pw.println(line);
      }
      pw.close();
      br.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

文件夾迭代

這里只需要用到一個(gè)File類,但需要用里面的一些方法來判斷是文件還是文件夾

isFile():是否是文件

isDirectory():是否是文件夾

還需要通過遞歸操作,將目錄下的所有子目錄也進(jìn)行迭代。

多線程處理

使用多線程的目的肯定是為了提升程序的效率。

因?yàn)樵谶M(jìn)行網(wǎng)絡(luò)數(shù)據(jù)爬取時(shí),一般都是同時(shí)爬取多個(gè)網(wǎng)頁(yè)的數(shù)據(jù),而不是單個(gè)網(wǎng)頁(yè),因此在項(xiàng)目開發(fā)中我們需要通過多線程,來讓程序同時(shí)完成多個(gè)操作。

多線程有兩種實(shí)現(xiàn)方式:

1)繼承Thread類

2)實(shí)現(xiàn)Runnable接口

使用多線程時(shí),還有兩個(gè)必須注意的方法:

1)start()啟動(dòng)線程

2)run()編寫線程執(zhí)行的主體。

先來完成一個(gè)倒計(jì)時(shí)功能:

public class ThreadDemo {
  public static void main(String[] args) {
    // new MyThread().start();
    // new Thread() {
    // public void run() {
    // for (int i = 10; i >= 0; i--) {
    // System.out.println("剩余時(shí)間:" + i);
    // try {
    // Thread.sleep(100);
    // } catch (InterruptedException e) {
    // e.printStackTrace();
    // }
    // }
    // }
    // }.start();
    // new Thread(new MyRunnable()).start();
  }
}

//繼承Thread類必須重寫run類
class MyThread extends Thread {
  @Override
  public void run() {
    for (int i = 10; i >= 0; i--) {
      System.out.println("剩余時(shí)間:" + i);
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}
class MyRunnable implements Runnable {
  @Override
  public void run() {
    for (int i = 10; i >= 0; i--) {
      System.out.println("剩余時(shí)間:" + i);
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

類集處理

List:允許重復(fù),可以根據(jù)下標(biāo)來取得數(shù)據(jù),會(huì)按照放入的順序來存儲(chǔ)數(shù)據(jù)。

    ArrayList:以數(shù)組的形式存儲(chǔ),適合不經(jīng)常變動(dòng),但經(jīng)常查詢的數(shù)據(jù)集。

    LinkedList:以鏈表的形式存儲(chǔ),適合經(jīng)常變動(dòng)的數(shù)據(jù)集,但是不經(jīng)常查詢

public class ListDemo {
  public static void main(String[] args) {
    LinkedList<Integer> list1 = new LinkedList<>();
    for (int i = 0; i <= 100000; i++) {
      list1.add(i);
    }
    long start = System.currentTimeMillis();
    for (int i = 0; i <= 100000; i++) {
      list1.get(i);
    }
    long end = System.currentTimeMillis();
    System.out.println("ArrayList: " + (end - start) + " ms");
  }
}

Set:不允許重復(fù),存儲(chǔ)順序看心情,沒辦法根據(jù)下標(biāo)取得數(shù)據(jù)

    HashSet:散列排序(沒有順序)

    TreeSet:二叉樹排序,按照固定的規(guī)則來排序,TreeSet中的內(nèi)容必須實(shí)現(xiàn)一個(gè)Comparable的接口,并且必須覆寫compareTo的方法,根據(jù)給定的規(guī)則來排序。

public class SetDemo {
  public static void main(String[] args) {
    Set<Person> set = new TreeSet<>();
    set.add(new Person("張三", 12));
    set.add(new Person("李四", 22));
    set.add(new Person("王五", 42));
    set.add(new Person("王八", 42));
    set.add(new Person("趙六", 32));
    System.out.println(set);
  }
}

class Person implements Comparable<Person> {
  private String name;
  private Integer age;

  public Person() {
    super();
  }

  public Person(String name, Integer age) {
    super();
    this.name = name;
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Integer getAge() {
    return age;
  }

  public void setAge(Integer age) {
    this.age = age;
  }

  @Override
  public String toString() {
    return "Person [name=" + name + ", age=" + age + "]";
  }
  @Override
  public int compareTo(Person o) {
    if (this.age > o.age) {
      return 1;
    } else if (this.age < o.age) {
      return -1;
    }
    if (this.name.equals(o.name)) {
      return 0;
    }
    return 1;
  }
}

Map:key-value形式,可以根據(jù)key取得value,key按照Set集合的模式來保存。

    HashMap:散列

    TreeMap:有順序

對(duì)于Map集合,要求能夠循環(huán)迭代出里面的所有數(shù)據(jù)。

所以必須掌握Map的循環(huán)方法。

public class MapDemo {
  public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<>();
    map.put("方便面", 20);
    map.put("火腿腸", 120);
    map.put("礦泉水", 20);
    map.put("可樂", 30);

    // Map集合如果想迭代必須先按照key來進(jìn)行迭代,
    // 再根key查找value
    Set<String> keySet = map.keySet();
    for (String key : keySet) {
      System.out.println(key + " ---> " + map.get(key));
    }
  }
}

小結(jié):

本篇對(duì)于java封裝、繼承、多態(tài)三大特性,IO操作,線程管理,類集處理(List、Set、Map)進(jìn)行了闡述以及代碼實(shí)現(xiàn)。

到此,對(duì)于網(wǎng)頁(yè)數(shù)據(jù)的爬寫的知識(shí)準(zhǔn)備的可以了,下一篇我會(huì)先對(duì)一個(gè)文件進(jìn)行數(shù)據(jù)爬取,然后再對(duì)網(wǎng)頁(yè)上的數(shù)據(jù)代碼實(shí)現(xiàn)爬蟲功能

到此這篇關(guān)于Java實(shí)現(xiàn)網(wǎng)絡(luò)數(shù)據(jù)提取所需知識(shí)點(diǎn)的文章就介紹到這了,更多相關(guān)Java實(shí)現(xiàn)網(wǎng)絡(luò)數(shù)據(jù)提取內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 配置pom.xml用maven打包java工程的方法(推薦)

    配置pom.xml用maven打包java工程的方法(推薦)

    下面小編就為大家?guī)硪黄渲胮om.xml用maven打包java工程的方法(推薦)。小編覺得挺不錯(cuò)的, 現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-06-06
  • Java多線程:生產(chǎn)者與消費(fèi)者案例

    Java多線程:生產(chǎn)者與消費(fèi)者案例

    這篇文章主要介紹了Java并發(fā)編程中的生產(chǎn)者與消費(fèi)者模型簡(jiǎn)述,多線程并發(fā)是Java編程中最終要的部分之一,需要的朋友可以參考下,希望能給你帶來幫助
    2021-07-07
  • Javaweb實(shí)戰(zhàn)之實(shí)現(xiàn)蛋糕訂購(gòu)系統(tǒng)

    Javaweb實(shí)戰(zhàn)之實(shí)現(xiàn)蛋糕訂購(gòu)系統(tǒng)

    隨著網(wǎng)絡(luò)的普及與發(fā)展,網(wǎng)上購(gòu)物逐漸成為一種主流消費(fèi)的方式。這篇文章主要介紹了通過JavaWeb制作一個(gè)線上蛋糕訂購(gòu)系統(tǒng),文中示例代碼講解詳細(xì),需要的朋友可以參考一下
    2021-12-12
  • java中如何使用泛型方法比較大小

    java中如何使用泛型方法比較大小

    這篇文章主要介紹了java中如何使用泛型方法比較大小,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Java的四種引用方式

    Java的四種引用方式

    這篇文章主要介紹了Java的四種引用方式,Java的引用方式主要包括強(qiáng)引用、軟引用、弱引用、虛引用;下面文章便來詳細(xì)介紹這四種引用方式,需要的朋友可以參考一下
    2021-10-10
  • Spring Boot中@RequestParam參數(shù)的5種情況說明

    Spring Boot中@RequestParam參數(shù)的5種情況說明

    這篇文章主要介紹了Spring Boot中@RequestParam參數(shù)的5種情況說明,具有很好的參考價(jià)值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 如何使用JaCoCo分析java單元測(cè)試覆蓋率

    如何使用JaCoCo分析java單元測(cè)試覆蓋率

    在做單元測(cè)試時(shí),代碼覆蓋率常常被拿來作為衡量測(cè)試好壞的指標(biāo),甚至,用代碼覆蓋率來考核測(cè)試任務(wù)完成情況,比如,代碼覆蓋率必須達(dá)到80%或 90%。于是乎,測(cè)試人員費(fèi)盡心思設(shè)計(jì)案例覆蓋代碼。下面我們來學(xué)習(xí)一下吧
    2019-06-06
  • 關(guān)于JSqlparser使用攻略(高效的SQL解析工具)

    關(guān)于JSqlparser使用攻略(高效的SQL解析工具)

    這篇文章主要介紹了關(guān)于JSqlparser使用攻略(高效的SQL解析工具),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Spring整合Redis完整實(shí)例代碼

    Spring整合Redis完整實(shí)例代碼

    這篇文章主要介紹了Spring整合Redis完整實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-04-04
  • 簡(jiǎn)單聊聊工作中常用的Java?Lambda表達(dá)式

    簡(jiǎn)單聊聊工作中常用的Java?Lambda表達(dá)式

    日常開發(fā)中,我們很多時(shí)候需要用到Java?8的Lambda表達(dá)式,它允許把函數(shù)作為一個(gè)方法的參數(shù),讓我們的代碼更優(yōu)雅、更簡(jiǎn)潔。所以整理了一波工作中常用的Lambda表達(dá)式??赐暌欢〞?huì)有幫助的
    2022-11-11

最新評(píng)論