ในช่วงแรก เรารวบรวมข้อมูลชื่อภายใต้ลิงก์นี้:
http://www.zhihu.com/explore/recommendations
แต่เห็นได้ชัดว่าหน้านี้ไม่สามารถหาคำตอบได้
หน้าคำถามที่สมบูรณ์จะมีลักษณะดังนี้:
http://www.zhihu.com/question/22355264
เมื่อพิจารณาให้ละเอียดยิ่งขึ้น aha คลาสการห่อหุ้มของเราจำเป็นต้องได้รับการบรรจุเพิ่มเติม อย่างน้อยก็จำเป็นต้องมี questionDescription เพื่อจัดเก็บคำอธิบายคำถาม:
นำเข้า java.util.ArrayList;
ชั้นเรียนสาธารณะ Zhihu {
คำถามสตริงสาธารณะ // คำถาม
สตริง questionDescription สาธารณะ // คำอธิบายคำถาม
สตริงสาธารณะ zhihuUrl;//ลิงก์หน้าเว็บ
public ArrayList<String> คำตอบ; // Array เพื่อเก็บคำตอบทั้งหมด
// Constructor เริ่มต้นข้อมูล
Zhihu สาธารณะ () {
คำถาม = "";
คำถามคำอธิบาย = "";
zhihuUrl = "";
คำตอบ = ใหม่ ArrayList<String>();
-
@แทนที่
สตริงสาธารณะ toString() {
กลับ "คำถาม:" + คำถาม + "/n" + "คำอธิบาย:" + คำถามคำอธิบาย + "/n"
+ "ลิงก์:" + zhihuUrl + "/nanswer:" + คำตอบ + "/n";
-
-
เราเพิ่มพารามิเตอร์ให้กับ Constructor ของ Zhihu เพื่อตั้งค่า URL เนื่องจากมีการกำหนด URL จึงสามารถบันทึกคำอธิบายและคำตอบของคำถามได้
มาเปลี่ยนวิธีการของ Spider ในการรับวัตถุ Zhihu และรับเฉพาะ URL:
ArrayList แบบคงที่ GetZhihu (เนื้อหาสตริง) {
// กำหนด ArrayList ไว้ล่วงหน้าเพื่อจัดเก็บผลลัพธ์
ArrayList<Zhihu> ผลลัพธ์ = ArrayList ใหม่<Zhihu>();
// ใช้เพื่อจับคู่ url ซึ่งเป็นลิงค์ไปยังคำถาม
รูปแบบ urlPattern = Pattern.compile("<h2>.+?question_link.+?href=/"(.+?)/".+?</h2>");
Matcher urlMatcher = urlPattern.matcher (เนื้อหา);
// ไม่ว่าจะมีวัตถุที่จับคู่สำเร็จหรือไม่
บูลีน isFind = urlMatcher.find();
ในขณะที่ (isFind) {
//กำหนดวัตถุ Zhihu เพื่อจัดเก็บข้อมูลที่บันทึกไว้
Zhihu zhihuTemp = Zhihu ใหม่(urlMatcher.group(1));
//เพิ่มผลการจับคู่ที่สำเร็จ
ผลลัพธ์ เพิ่ม(zhihuTemp);
// ดำเนินการค้นหาวัตถุที่ตรงกันต่อไป
isFind = urlMatcher.find();
-
ส่งคืนผลลัพธ์;
-
ต่อไป ในวิธีการก่อสร้างของ Zhihu รับข้อมูลโดยละเอียดทั้งหมดผ่าน URL
ก่อนอื่น เราต้องประมวลผล URL เนื่องจากสำหรับคำตอบบางข้อ URL ของมันคือ:
http://www.zhihu.com/question/22355264/answer/21102139
บางส่วนเป็นปัญหาเฉพาะเจาะจง และ URL ของมันคือ:
http://www.zhihu.com/question/22355264
เห็นได้ชัดว่าเราต้องการประเภทที่สอง ดังนั้นเราจึงจำเป็นต้องใช้กฎปกติเพื่อตัดลิงก์ประเภทแรกให้เป็นประเภทที่สอง ซึ่งสามารถทำได้โดยการเขียนฟังก์ชันใน Zhihu
// จัดการ url
บูลีน getRealUrl (URL สตริง) {
// เปลี่ยน http://www.zhihu.com/question/22355264/answer/21102139
//แปลงเป็นhttp://www.zhihu.com/question/22355264
// มิฉะนั้นไม่มีการเปลี่ยนแปลง
รูปแบบรูปแบบ = Pattern.compile("question/(.*?)/");
Matcher matcher = pattern.matcher(url);
ถ้า (matcher.find()) {
zhihuUrl = "http://www.zhihu.com/question/" + matcher.group(1);
} อื่น {
กลับเท็จ;
-
กลับเป็นจริง;
-
ขั้นตอนต่อไปคือการได้รับชิ้นส่วนต่างๆ
มาดูชื่อเรื่องกันก่อน:
เพียงเข้าใจคลาสนั้นในรูปแบบปกติ คำสั่งปกติสามารถเขียนเป็น: zm-editable-content/">(.+?)<
เรียกใช้เพื่อดูผลลัพธ์:
อุ๊ย ไม่เลว
ถัดไปคว้าคำอธิบายปัญหา:
อ๋อ หลักการเดียวกันนี้ รีบคว้าชั้นเรียนซะ เพราะมันควรจะเป็นตัวระบุเฉพาะของสิ่งนี้
วิธีการตรวจสอบ: คลิกขวาเพื่อดูซอร์สโค้ดของหน้า กด Ctrl+F เพื่อดูว่ามีสตริงอื่นๆ อยู่ในหน้าหรือไม่
ต่อมา หลังจากการตรวจสอบแล้ว มีบางอย่างผิดพลาดเกิดขึ้น:
คลาสที่อยู่หน้าเนื้อหาชื่อเรื่องและคำอธิบายจะเหมือนกัน
ที่สามารถจับภาพใหม่ได้โดยการปรับเปลี่ยนรูปแบบปกติเท่านั้น:
// ชื่อการแข่งขัน
pattern = Pattern.compile("zh-question-title.+?<h2.+?>(.+?)</h2>");
matcher = pattern.matcher (เนื้อหา);
ถ้า (matcher.find()) {
คำถาม = matcher.group(1);
-
// คำอธิบายการจับคู่
รูปแบบ=รูปแบบ
.compile("zh-question-detail.+?<div.+?>(.*?)</div>");
matcher = pattern.matcher (เนื้อหา);
ถ้า (matcher.find()) {
questionDescription = matcher.group(1);
-
สิ่งสุดท้ายคือการวนซ้ำเพื่อคว้าคำตอบ:
ข้อความปกติเบื้องต้นเบื้องต้น: /answer/content.+?<div.+?>(.*?)</div>
หลังจากเปลี่ยนโค้ดแล้ว เราจะพบว่าซอฟต์แวร์ทำงานช้าลงอย่างมาก เนื่องจากจำเป็นต้องไปที่หน้าเว็บแต่ละหน้าและบันทึกเนื้อหาในนั้น
ตัวอย่างเช่น หากมีคำถาม 20 ข้อที่แนะนำโดยบรรณาธิการ คุณจะต้องเข้าชมหน้าเว็บ 20 ครั้ง และความเร็วจะลดลง
ลองดูครับ ดูดี:
ตกลง ปล่อยให้มันเป็นเช่นนี้ไปก่อน ~ ครั้งต่อไปเราจะทำการปรับเปลี่ยนรายละเอียดบางอย่างต่อไป เช่น มัลติเธรด การเขียนสตรีม IO ในเครื่อง ฯลฯ
สิ่งที่แนบมาคือซอร์สโค้ดของโครงการ:
Zhihu.java
นำเข้า java.util.ArrayList;
นำเข้า java.util.regex.Matcher;
นำเข้า java.util.regex.Pattern;
ชั้นเรียนสาธารณะ Zhihu {
คำถามสตริงสาธารณะ // คำถาม
สตริง questionDescription สาธารณะ // คำอธิบายคำถาม
สตริงสาธารณะ zhihuUrl;//ลิงก์หน้าเว็บ
public ArrayList<String> คำตอบ; // Array เพื่อเก็บคำตอบทั้งหมด
// Constructor เริ่มต้นข้อมูล
Zhihu สาธารณะ (URL สตริง) {
//เริ่มต้นคุณสมบัติ
คำถาม = "";
คำถามคำอธิบาย = "";
zhihuUrl = "";
คำตอบ = ใหม่ ArrayList<String>();
// ตรวจสอบว่า url นั้นถูกกฎหมายหรือไม่
ถ้า (getRealUrl (url)) {
System.out.println("การรวบรวมข้อมูล" + zhihuUrl);
// รับรายละเอียดของคำถามและคำตอบตาม URL
เนื้อหาสตริง = Spider.SendGet (zhihuUrl);
รูปแบบลวดลาย;
ไม้ขีดไฟ ไม้ขีดไฟ;
// ชื่อการแข่งขัน
pattern = Pattern.compile("zh-question-title.+?<h2.+?>(.+?)</h2>");
matcher = pattern.matcher (เนื้อหา);
ถ้า (matcher.find()) {
คำถาม = matcher.group(1);
-
// คำอธิบายการจับคู่
รูปแบบ=รูปแบบ
.compile("zh-question-detail.+?<div.+?>(.*?)</div>");
matcher = pattern.matcher (เนื้อหา);
ถ้า (matcher.find()) {
questionDescription = matcher.group(1);
-
//จับคู่คำตอบ
pattern = Pattern.compile("/answer/content.+?<div.+?>(.*?)</div>");
matcher = pattern.matcher (เนื้อหา);
บูลีน isFind = matcher.find();
ในขณะที่ (isFind) {
answer.add(matcher.group(1));
isFind = matcher.find();
-
-
-
// หยิบคำถาม คำอธิบาย และคำตอบของคุณเองตาม URL ของคุณเอง
บูลีนสาธารณะ getAll () {
กลับเป็นจริง;
-
// จัดการ url
บูลีน getRealUrl (URL สตริง) {
// เปลี่ยน http://www.zhihu.com/question/22355264/answer/21102139
//แปลงเป็นhttp://www.zhihu.com/question/22355264
// มิฉะนั้นไม่มีการเปลี่ยนแปลง
รูปแบบรูปแบบ = Pattern.compile("question/(.*?)/");
Matcher matcher = pattern.matcher(url);
ถ้า (matcher.find()) {
zhihuUrl = "http://www.zhihu.com/question/" + matcher.group(1);
} อื่น {
กลับเท็จ;
-
กลับเป็นจริง;
-
@แทนที่
สตริงสาธารณะ toString() {
กลับ "คำถาม:" + คำถาม + "/n" + "คำอธิบาย:" + คำถามคำอธิบาย + "/n"
+ "ลิงก์:" + zhihuUrl + "/nคำตอบ:" + answer.size() + "/n";
-
-
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();
-
-
ส่งคืนผลลัพธ์;
-
// รับเนื้อหา Zhihu ทั้งหมดที่แนะนำโดยบรรณาธิการ
ArrayList แบบคงที่ <Zhihu> GetRecommendations (เนื้อหาสตริง) {
// กำหนด ArrayList ไว้ล่วงหน้าเพื่อจัดเก็บผลลัพธ์
ArrayList<Zhihu> ผลลัพธ์ = ArrayList ใหม่<Zhihu>();
// ใช้เพื่อจับคู่ url ซึ่งเป็นลิงค์ไปยังคำถาม
รูปแบบรูปแบบ = รูปแบบ
.compile("<h2>.+?question_link.+?href=/"(.+?)/".+?</h2>");
Matcher matcher = pattern.matcher(เนื้อหา);
// ไม่ว่าจะมีวัตถุที่จับคู่สำเร็จหรือไม่
บูลีน isFind = matcher.find();
ในขณะที่ (isFind) {
//กำหนดวัตถุ Zhihu เพื่อจัดเก็บข้อมูลที่บันทึกไว้
Zhihu zhihuTemp = Zhihu ใหม่(matcher.group(1));
//เพิ่มผลการจับคู่ที่สำเร็จ
ผลลัพธ์ เพิ่ม(zhihuTemp);
// ดำเนินการค้นหาวัตถุที่ตรงกันต่อไป
isFind = matcher.find();
-
ส่งคืนผลลัพธ์;
-
-
Main.java
นำเข้า java.util.ArrayList;
ชั้นเรียนสาธารณะหลัก {
โมฆะคงที่สาธารณะ main (String [] args) {
// กำหนดลิงค์ที่จะเข้าชม
URL สตริง = "http://www.zhihu.com/explore/recommendations";
//เข้าถึงลิงค์และรับเนื้อหาของหน้า
เนื้อหาสตริง = Spider.SendGet (url);
// รับคำแนะนำจากบรรณาธิการ
ArrayList<Zhihu> myZhihu = Spider.GetRecommendations(เนื้อหา);
// พิมพ์ผลลัพธ์
System.out.println(myZhihu);
-
-
ข้างต้นคือบันทึกการคว้าคำตอบของ Zhihu ทั้งหมด ซึ่งมีรายละเอียดมาก เพื่อนๆ ที่ต้องการความช่วยเหลือสามารถอ้างอิงถึงมันได้