Zhihu คือชุมชนถามตอบออนไลน์ที่แท้จริงซึ่งมีบรรยากาศชุมชนที่เป็นมิตร มีเหตุผล และจริงจัง ซึ่งเชื่อมโยงชนชั้นสูงจากทุกสาขาอาชีพ พวกเขาแบ่งปันความรู้ ประสบการณ์ และข้อมูลเชิงลึกทางวิชาชีพของกันและกัน และให้ข้อมูลคุณภาพสูงสำหรับอินเทอร์เน็ตของจีนอย่างต่อเนื่อง
ขั้นแรก ใช้เวลาสามถึงห้านาทีในการออกแบบโลโก้ = =ในฐานะโปรแกรมเมอร์ ฉันมีหัวใจในการเป็นศิลปินมาโดยตลอด!
โอเค มันเป็นการชั่วคราวนิดหน่อย ดังนั้นฉันจะจัดการกับมันในตอนนี้
ต่อไป เราเริ่มสร้างโปรแกรมรวบรวมข้อมูลของ Zhihu
ขั้นแรก กำหนดเป้าหมายแรก: คำแนะนำจากบรรณาธิการ
ลิงค์เว็บ: http://www.zhihu.com/explore/recommendations
เราแก้ไขโค้ดสุดท้ายเล็กน้อยเพื่อให้สามารถรับเนื้อหาของหน้าได้ก่อน:
นำเข้า java.io.*;
นำเข้า java.net.*;
นำเข้า java.util.regex.*;
ชั้นเรียนสาธารณะหลัก {
SendGet สตริงคงที่ (URL ของสตริง) {
//กำหนดสตริงเพื่อจัดเก็บเนื้อหาหน้าเว็บ
ผลลัพธ์สตริง = "";
//กำหนดสตรีมอินพุตอักขระบัฟเฟอร์
BufferedReader ใน = null;
พยายาม {
//แปลงสตริงเป็นวัตถุ url
URL realUrl = URL ใหม่ (URL);
// เริ่มต้นการเชื่อมโยงไปยัง url นั้น
การเชื่อมต่อ URLConnection = realUrl.openConnection();
// เริ่มการเชื่อมต่อจริง
การเชื่อมต่อเชื่อมต่อ();
//เริ่มต้นสตรีมอินพุต BufferedReader เพื่ออ่านการตอบสนองของ URL
ใน = ใหม่ BufferedReader (InputStreamReader ใหม่ (
การเชื่อมต่อgetInputStream()));
// ใช้เพื่อเก็บข้อมูลของแต่ละแถวที่บันทึกไว้ชั่วคราว
เส้นสาย;
ในขณะที่ ((line = in.readLine()) != null) {
// สำรวจแต่ละแถวที่ถูกจับและเก็บไว้ในผลลัพธ์
ผลลัพธ์ += บรรทัด;
-
} จับ (ข้อยกเว้นจ) {
System.out.println("ข้อยกเว้นเกิดขึ้นเมื่อส่งคำขอ GET!" + e);
e.printStackTrace();
-
// ใช้ในที่สุดเพื่อปิดสตรีมอินพุต
ในที่สุด {
พยายาม {
ถ้า (ใน != null) {
ใน.ปิด();
-
} จับ (ข้อยกเว้น e2) {
e2.printStackTrace();
-
-
ส่งคืนผลลัพธ์;
-
RegexString สตริงแบบคงที่ (สตริง targetStr, PatternStr สตริง) {
// กำหนดเทมเพลตสไตล์โดยใช้นิพจน์ทั่วไป และเนื้อหาที่จะบันทึกจะอยู่ในวงเล็บ
// เทียบเท่ากับการวางกับดัก และถ้าตรงกัน มันจะตกลงไป
รูปแบบรูปแบบ = Pattern.compile (patternStr);
//กำหนดตัวจับคู่สำหรับการจับคู่
Matcher matcher = pattern.matcher(targetStr);
//หากพบ
ถ้า (matcher.find()) {
// พิมพ์ผลลัพธ์ออกมา
ส่งคืน matcher.group (1);
-
ส่งคืน "ไม่มีอะไร";
-
โมฆะคงที่สาธารณะ main (String [] args) {
// กำหนดลิงค์ที่จะเข้าชม
URL สตริง = "http://www.zhihu.com/explore/recommendations";
//เข้าถึงลิงค์และรับเนื้อหาของหน้า
ผลลัพธ์สตริง = SendGet (url);
// ใช้นิพจน์ทั่วไปเพื่อจับคู่เนื้อหา src ของรูปภาพ
//String imgSrc = RegexString(result, "src=/"(.+?)/"");
// พิมพ์ผลลัพธ์
System.out.println (ผลลัพธ์);
-
-
ไม่มีปัญหาหลังจากใช้งานแล้ว ขั้นตอนต่อไปคือปัญหาการจับคู่ปกติ
ก่อนอื่น เรามาตอบคำถามทั้งหมดในหน้านี้กันก่อน
คลิกขวาที่ชื่อและตรวจสอบองค์ประกอบ:
อ๋อ คุณจะเห็นว่าชื่อจริงๆ แล้วเป็นแท็ก ซึ่งเป็นไฮเปอร์ลิงก์ และสิ่งที่แตกต่างจากไฮเปอร์ลิงก์อื่นๆ ควรเป็นคลาส ซึ่งก็คือตัวเลือกคลาส
ดังนั้นข้อความปกติของเราจึงออกมา: question_link.+?href=/"(.+?)/"
เรียกใช้ฟังก์ชัน RegexString และส่งพารามิเตอร์:
โมฆะคงที่สาธารณะ main (String [] args) {
// กำหนดลิงค์ที่จะเข้าชม
URL สตริง = "http://www.zhihu.com/explore/recommendations";
//เข้าถึงลิงค์และรับเนื้อหาของหน้า
ผลลัพธ์สตริง = SendGet (url);
// ใช้นิพจน์ทั่วไปเพื่อจับคู่เนื้อหา src ของรูปภาพ
สตริง imgSrc = RegexString(result, "question_link.+?>(.+?)<");
// พิมพ์ผลลัพธ์
System.out.println(imgSrc);
-
อา ฮ่า คุณจะเห็นว่าเราบันทึกชื่อได้สำเร็จ (หมายเหตุ มีเพียงอันเดียว):
เดี๋ยวก่อน ความยุ่งวุ่นวายทั้งหมดนี้คืออะไร? -
อย่าเครียด=.. = มันเป็นเพียงตัวอักษรที่อ่านไม่ออก
สำหรับปัญหาการเข้ารหัส โปรดดู: ชุดอักขระ HTML
โดยทั่วไปแล้ว การเข้ารหัสกระแสหลักที่รองรับภาษาจีนได้ดีกว่าคือการเข้ารหัส UTF-8, GB2312 และ GBK
หน้าเว็บสามารถตั้งค่าการเข้ารหัสหน้าเว็บผ่านชุดอักขระของเมตาแท็กได้ ตัวอย่างเช่น:
<meta charset="utf-8" />
คลิกขวาเพื่อดูซอร์สโค้ดของหน้า:
อย่างที่คุณเห็น Zhihu ใช้การเข้ารหัส UTF-8
ที่นี่ฉันจะอธิบายให้คุณทราบถึงความแตกต่างระหว่างการดูซอร์สโค้ดของหน้าและการตรวจสอบองค์ประกอบ
การดูซอร์สโค้ดของหน้าจะแสดงโค้ดทั้งหมดของทั้งหน้า โดยไม่ได้จัดรูปแบบตามแท็ก HTML ซึ่งเทียบเท่ากับการดูซอร์สโค้ดโดยตรง วิธีนี้จะมีประโยชน์มากกว่าสำหรับการดูข้อมูลของหน้าเว็บทั้งหมด เช่น เมตาดาต้า
ตรวจสอบองค์ประกอบหรือเบราว์เซอร์บางตัวเรียกว่าองค์ประกอบมุมมอง ซึ่งคือการดูองค์ประกอบที่คุณคลิกขวา เช่น div หรือ img เหมาะสำหรับการดูแอตทริบิวต์และแท็กของวัตถุทีละรายการมากกว่า
โอเค ตอนนี้เรารู้แล้วว่าปัญหาอยู่ที่การเข้ารหัส ขั้นตอนต่อไปคือการแปลงการเข้ารหัสของเนื้อหาที่บันทึกไว้
การใช้งานใน Java นั้นง่ายมาก เพียงระบุวิธีการเข้ารหัสใน InputStreamReader:
//เริ่มต้นสตรีมอินพุต BufferedReader เพื่ออ่านการตอบสนองของ URL
ใน = ใหม่ BufferedReader (InputStreamReader ใหม่ (
Connection.getInputStream(),"UTF-8"));
หากคุณรันโปรแกรมอีกครั้งในเวลานี้ คุณจะพบว่าสามารถแสดงชื่อได้ตามปกติ:
ตกลง! ดีมาก!
แต่ตอนนี้มีเพียงชื่อเดียว เราต้องการทุกชื่อ
เราแก้ไขนิพจน์ทั่วไปเล็กน้อยและจัดเก็บผลการค้นหาไว้ใน ArrayList:
นำเข้า java.io.*;
นำเข้า java.net.*;
นำเข้า java.util.ArrayList;
นำเข้า java.util.regex.*;
ชั้นเรียนสาธารณะหลัก {
SendGet สตริงคงที่ (URL ของสตริง) {
//กำหนดสตริงเพื่อจัดเก็บเนื้อหาหน้าเว็บ
ผลลัพธ์สตริง = "";
//กำหนดสตรีมอินพุตอักขระบัฟเฟอร์
BufferedReader ใน = null;
พยายาม {
//แปลงสตริงเป็นวัตถุ url
URL realUrl = URL ใหม่ (URL);
// เริ่มต้นการเชื่อมโยงไปยัง url นั้น
การเชื่อมต่อ URLConnection = realUrl.openConnection();
// เริ่มการเชื่อมต่อจริง
การเชื่อมต่อเชื่อมต่อ();
//เริ่มต้นสตรีมอินพุต BufferedReader เพื่ออ่านการตอบสนองของ URL
ใน = ใหม่ BufferedReader (InputStreamReader ใหม่ (
Connection.getInputStream(), "UTF-8"));
// ใช้เพื่อเก็บข้อมูลของแต่ละแถวที่บันทึกไว้ชั่วคราว
เส้นสาย;
ในขณะที่ ((line = in.readLine()) != null) {
// สำรวจแต่ละแถวที่ถูกจับและเก็บไว้ในผลลัพธ์
ผลลัพธ์ += บรรทัด;
-
} จับ (ข้อยกเว้นจ) {
System.out.println("ข้อยกเว้นเกิดขึ้นเมื่อส่งคำขอ GET!" + e);
e.printStackTrace();
-
// ใช้ในที่สุดเพื่อปิดสตรีมอินพุต
ในที่สุด {
พยายาม {
ถ้า (ใน != null) {
ใน.ปิด();
-
} จับ (ข้อยกเว้น e2) {
e2.printStackTrace();
-
-
ส่งคืนผลลัพธ์;
-
ArrayList แบบคงที่ RegexString (String targetStr, String patternStr) {
// กำหนด ArrayList ไว้ล่วงหน้าเพื่อจัดเก็บผลลัพธ์
ArrayList<String> ผลลัพธ์ = ArrayList ใหม่<String>();
// กำหนดเทมเพลตสไตล์โดยใช้นิพจน์ทั่วไป และเนื้อหาที่จะบันทึกจะอยู่ในวงเล็บ
รูปแบบรูปแบบ = Pattern.compile (patternStr);
//กำหนดตัวจับคู่สำหรับการจับคู่
Matcher matcher = pattern.matcher(targetStr);
//หากพบ
บูลีน isFind = matcher.find();
// ใช้ลูปเพื่อค้นหาและแทนที่เคลวินทั้งหมดในประโยคและเพิ่มเนื้อหาลงใน sb
ในขณะที่ (isFind) {
//เพิ่มผลการจับคู่ที่สำเร็จ
result.add(matcher.group(1));
// ดำเนินการค้นหาวัตถุที่ตรงกันต่อไป
isFind = matcher.find();
-
ส่งคืนผลลัพธ์;
-
โมฆะคงที่สาธารณะ main (String [] args) {
// กำหนดลิงค์ที่จะเข้าชม
URL สตริง = "http://www.zhihu.com/explore/recommendations";
//เข้าถึงลิงค์และรับเนื้อหาของหน้า
ผลลัพธ์สตริง = SendGet (url);
// ใช้นิพจน์ทั่วไปเพื่อจับคู่เนื้อหา src ของรูปภาพ
ArrayList<String> imgSrc = RegexString(result, "question_link.+?>(.+?)<");
// พิมพ์ผลลัพธ์
System.out.println(imgSrc);
-
-
ซึ่งจะตรงกับผลลัพธ์ทั้งหมด (เนื่องจาก ArrayList ถูกพิมพ์โดยตรง จึงจะมีวงเล็บเหลี่ยมและลูกน้ำ):
ตกลง นี่เป็นก้าวแรกของโปรแกรมรวบรวมข้อมูล Zhihu
แต่เราจะเห็นว่าไม่มีทางที่จะรวบรวมคำถามและคำตอบทั้งหมดด้วยวิธีนี้ได้
เราจำเป็นต้องออกแบบคลาสการห่อหุ้ม Zhihu เพื่อจัดเก็บวัตถุที่ถูกจับทั้งหมด
ซอร์สโค้ด Zhihu.java:
นำเข้า java.util.ArrayList;
ชั้นเรียนสาธารณะ Zhihu {
คำถามสตริงสาธารณะ // คำถาม
สตริงสาธารณะ zhihuUrl;//ลิงก์หน้าเว็บ
public ArrayList<String> คำตอบ; // Array เพื่อเก็บคำตอบทั้งหมด
// Constructor เริ่มต้นข้อมูล
Zhihu สาธารณะ () {
คำถาม = "";
zhihuUrl = "";
คำตอบ = ใหม่ ArrayList<String>();
-
@แทนที่
สตริงสาธารณะ toString() {
กลับ "คำถาม:" + คำถาม + "/nLink:" + zhihuUrl + "/nAnswer:" + คำตอบ + "/n";
-
-
สร้างคลาส Spider ใหม่เพื่อจัดเก็บฟังก์ชันที่ใช้กันทั่วไปของโปรแกรมรวบรวมข้อมูล
ซอร์สโค้ด Spider.java:
นำเข้า java.io.BufferedReader;
นำเข้า java.io.InputStreamReader;
นำเข้า java.net.URL;
นำเข้า java.net.URLConnection;
นำเข้า java.util.ArrayList;
นำเข้า java.util.regex.Matcher;
นำเข้า java.util.regex.Pattern;
แมงมุมคลาสสาธารณะ {
SendGet สตริงคงที่ (URL ของสตริง) {
//กำหนดสตริงเพื่อจัดเก็บเนื้อหาหน้าเว็บ
ผลลัพธ์สตริง = "";
//กำหนดสตรีมอินพุตอักขระบัฟเฟอร์
BufferedReader ใน = null;
พยายาม {
//แปลงสตริงเป็นวัตถุ url
URL realUrl = URL ใหม่ (URL);
// เริ่มต้นการเชื่อมโยงไปยัง url นั้น
การเชื่อมต่อ URLConnection = realUrl.openConnection();
// เริ่มการเชื่อมต่อจริง
การเชื่อมต่อเชื่อมต่อ();
//เริ่มต้นสตรีมอินพุต BufferedReader เพื่ออ่านการตอบสนองของ URL
ใน = ใหม่ BufferedReader (InputStreamReader ใหม่ (
Connection.getInputStream(), "UTF-8"));
// ใช้เพื่อเก็บข้อมูลของแต่ละแถวที่บันทึกไว้ชั่วคราว
เส้นสาย;
ในขณะที่ ((line = in.readLine()) != null) {
// สำรวจแต่ละแถวที่ถูกจับและเก็บไว้ในผลลัพธ์
ผลลัพธ์ += บรรทัด;
-
} จับ (ข้อยกเว้นจ) {
System.out.println("ข้อยกเว้นเกิดขึ้นเมื่อส่งคำขอ GET!" + e);
e.printStackTrace();
-
// ใช้ในที่สุดเพื่อปิดสตรีมอินพุต
ในที่สุด {
พยายาม {
ถ้า (ใน != null) {
ใน.ปิด();
-
} จับ (ข้อยกเว้น e2) {
e2.printStackTrace();
-
-
ส่งคืนผลลัพธ์;
-
ArrayList แบบคงที่ GetZhihu (เนื้อหาสตริง) {
// กำหนด ArrayList ไว้ล่วงหน้าเพื่อจัดเก็บผลลัพธ์
ArrayList<Zhihu> ผลลัพธ์ = ArrayList ใหม่<Zhihu>();
// ใช้เพื่อจับคู่ชื่อเรื่อง
รูปแบบ questionPattern = Pattern.compile("question_link.+?>(.+?)<");
Matcher questionMatcher = questionPattern.matcher(เนื้อหา);
// ใช้เพื่อจับคู่ url ซึ่งเป็นลิงค์ไปยังคำถาม
รูปแบบ urlPattern = Pattern.compile("question_link.+?href=/"(.+?)/"");
Matcher urlMatcher = urlPattern.matcher (เนื้อหา);
// ทั้งคำถามและลิงก์ต้องตรงกัน
บูลีน isFind = questionMatcher.find() && urlMatcher.find();
ในขณะที่ (isFind) {
//กำหนดวัตถุ Zhihu เพื่อจัดเก็บข้อมูลที่บันทึกไว้
Zhihu zhuhuTemp = ใหม่ Zhihu();
zhuhuTemp.question = questionMatcher.group(1);
zhuhuTemp.zhihuUrl = "http://www.zhihu.com" + urlMatcher.group(1);
//เพิ่มผลการจับคู่ที่สำเร็จ
ผลลัพธ์ เพิ่ม(zhuhuTemp);
// ดำเนินการค้นหาวัตถุที่ตรงกันต่อไป
isFind = questionMatcher.find() && urlMatcher.find();
-
ส่งคืนผลลัพธ์;
-
-
วิธีการหลักสุดท้ายมีหน้าที่ในการโทร
นำเข้า java.util.ArrayList;
ชั้นเรียนสาธารณะหลัก {
โมฆะคงที่สาธารณะ main (String [] args) {
// กำหนดลิงค์ที่จะเข้าชม
URL สตริง = "http://www.zhihu.com/explore/recommendations";
//เข้าถึงลิงค์และรับเนื้อหาของหน้า
เนื้อหาสตริง = Spider.SendGet (url);
// รับวัตถุ Zhihu ทั้งหมดในหน้านี้
ArrayList<Zhihu> myZhihu = Spider.GetZhihu(เนื้อหา);
// พิมพ์ผลลัพธ์
System.out.println(myZhihu);
-
-
โอเค แค่นั้นแหละ. เรียกใช้และดูผลลัพธ์:
ผลลัพธ์ที่ดี
ขั้นตอนต่อไปคือการเข้าถึงลิงก์และรับคำตอบทั้งหมด
เราจะแนะนำมันในครั้งต่อไป
ข้างต้นนี้เป็นการแนะนำสั้นๆ เกี่ยวกับการใช้ Java เพื่อรวบรวมเนื้อหาที่แนะนำโดยบรรณาธิการของ Zhihu มีรายละเอียดมากและเข้าใจง่าย เพื่อนๆ ที่ต้องการสามารถอ้างอิงและขยายความได้อย่างอิสระ 555