في المرحلة الأولى، قمنا بالزحف إلى العنوان تحت هذا الرابط:
http://www.zhihu.com/explore/recommendations
لكن من الواضح أن هذه الصفحة لا يمكنها الحصول على الإجابة.
ستبدو صفحة الأسئلة الكاملة كما يلي:
http://www.zhihu.com/question/22355264
بإلقاء نظرة فاحصة، آها، تحتاج فئة التغليف الخاصة بنا إلى مزيد من التعبئة، على الأقل هناك حاجة إلى وصف سؤال لتخزين وصف السؤال:
import java.util.ArrayList;
الطبقة العامة Zhihu {
سؤال السلسلة العامة؛ // سؤال
وصف السلسلة العامة // وصف السؤال
public String zhihuUrl;// رابط صفحة الويب
إجابات ArrayList<String> العامة؛ // مصفوفة لتخزين جميع الإجابات
// يقوم المُنشئ بتهيئة البيانات
تشيهو العامة () {
سؤال = "";
questionDescription = "";
zhihuUrl = "";
الإجابات = new ArrayList<String>();
}
@تجاوز
سلسلة عامة إلى سلسلة () {
إرجاع "السؤال:" + السؤال + "/n" + "الوصف:" + questionDescription + "/n"
+ "الرابط:" + zhihuUrl + "/nanswer:" + Answers + "/n";
}
}
نضيف معلمة إلى مُنشئ Zhihu لتعيين قيمة عنوان URL. نظرًا لأنه تم تحديد عنوان URL، يمكن التقاط الوصف والإجابة على السؤال.
دعونا نغير طريقة Spider في الحصول على كائنات Zhihu ونحصل على عنوان URL فقط:
ArrayList ثابت<Zhihu> GetZhihu(محتوى السلسلة) {
// حدد قائمة ArrayList مسبقًا لتخزين النتائج
ArrayList<Zhihu> results = new ArrayList<Zhihu>();
// يُستخدم لمطابقة عنوان url، وهو رابط السؤال
Pattern urlPattern = Pattern.compile("<h2>.+?question_link.+?href=/"(.+?)/".+?</h2>");
Matcher urlMatcher = urlPattern.matcher(content);
// ما إذا كان هناك كائن مطابق ناجح
boolean isFind = urlMatcher.find();
بينما (isFind) {
// حدد كائن Zhihu لتخزين المعلومات الملتقطة
Zhihu zhihuTemp = new Zhihu(urlMatcher.group(1));
// أضف نتائج مطابقة ناجحة
results.add(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(سلسلة رابط) {
// تغيير 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>");
المطابق = Pattern.matcher(content);
إذا (matcher.find()) {
سؤال = matcher.group(1);
}
// وصف المباراة
Pattern=Pattern
.compile("zh-question-detail.+?<div.+?>(.*?)</div>");
المطابق = Pattern.matcher(content);
إذا (matcher.find()) {
questionDescription = matcher.group(1);
}
آخر شيء هو التكرار للحصول على الإجابة:
البيان العادي الأولي: /answer/content.+?<div.+?>(.*?)</div>
بعد تغيير الكود، سنجد أن البرنامج يعمل بشكل أبطأ بشكل ملحوظ لأنه يحتاج إلى زيارة كل صفحة ويب والتقاط المحتوى الموجود عليها.
على سبيل المثال، إذا كان هناك 20 سؤالًا أوصى بها المحرر، فأنت بحاجة لزيارة صفحة الويب 20 مرة، وستنخفض السرعة.
جربه، يبدو جيدًا:
حسنًا، لنترك الأمر على هذا النحو الآن ~ في المرة القادمة سنستمر في إجراء بعض التعديلات التفصيلية، مثل تعدد الخيوط، وكتابة تدفقات الإدخال والإخراج محليًا، وما إلى ذلك.
مرفق هو الكود المصدري للمشروع:
Zhihu.java
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
الطبقة العامة Zhihu {
سؤال السلسلة العامة؛ // سؤال
وصف السلسلة العامة // وصف السؤال
public String zhihuUrl;// رابط صفحة الويب
إجابات ArrayList<String> العامة؛ // مصفوفة لتخزين جميع الإجابات
// يقوم المُنشئ بتهيئة البيانات
Zhihu العام (سلسلة URL) {
// تهيئة الخصائص
سؤال = "";
questionDescription = "";
zhihuUrl = "";
الإجابات = new ArrayList<String>();
// تحديد ما إذا كان عنوان URL قانونيًا أم لا
إذا (getRealUrl(url)) {
System.out.println("الزحف" + zhihuUrl);
// احصل على تفاصيل السؤال والإجابة بناءً على عنوان url
محتوى السلسلة = Spider.SendGet(zhihuUrl);
نمط النمط؛
مُطابق؛
// عنوان المباراة
Pattern = Pattern.compile("zh-question-title.+?<h2.+?>(.+?)</h2>");
المطابق = Pattern.matcher(content);
إذا (matcher.find()) {
سؤال = matcher.group(1);
}
// وصف المباراة
Pattern=Pattern
.compile("zh-question-detail.+?<div.+?>(.*?)</div>");
المطابق = Pattern.matcher(content);
إذا (matcher.find()) {
questionDescription = matcher.group(1);
}
// تطابق الإجابة
Pattern = Pattern.compile("/answer/content.+?<div.+?>(.*?)</div>");
المطابق = Pattern.matcher(content);
boolean isFind = matcher.find();
بينما (isFind) {
Answers.add(matcher.group(1));
isFind = matcher.find();
}
}
}
// احصل على أسئلتك وأوصافك وإجاباتك بناءً على عنوان URL الخاص بك
getAll المنطقية العامة () {
عودة صحيحة؛
}
// التعامل مع عنوان url
منطقية getRealUrl(سلسلة رابط) {
// تغيير 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);
} آخر {
عودة كاذبة.
}
عودة صحيحة؛
}
@تجاوز
سلسلة عامة إلى سلسلة () {
إرجاع "السؤال:" + السؤال + "/n" + "الوصف:" + questionDescription + "/n"
+ "الرابط:" + zhihuUrl + "/nAnswer:" + Answers.size() + "/n";
}
}
Spider.java
import java.io.BufferedReader;
استيراد java.io.InputStreamReader؛
استيراد java.net.URL؛
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
عنكبوت الطبقة العامة {
سلسلة ثابتة SendGet(سلسلة URL) {
// تحديد سلسلة لتخزين محتوى صفحة الويب
نتيجة السلسلة = ""؛
// تحديد دفق إدخال الأحرف المخزنة مؤقتًا
BufferedReader in = null;
يحاول {
// تحويل السلسلة إلى كائن URL
URL realUrl = عنوان URL الجديد(url);
// تهيئة رابط إلى عنوان url هذا
اتصال URLConnection = realUrl.openConnection();
// ابدأ الاتصال الفعلي
Connection.connect();
// تهيئة دفق إدخال BufferedReader لقراءة استجابة عنوان URL
in = new BufferedReader(new InputStreamReader(
Connection.getInputStream(), "UTF-8"));
// يُستخدم لتخزين بيانات كل صف تم التقاطه مؤقتًا
خط السلسلة؛
بينما ((line = in.readLine()) != null) {
// اجتياز كل صف تم التقاطه وتخزينه في النتيجة
النتيجة += السطر؛
}
} قبض (الاستثناء ه) {
System.out.println("حدث استثناء عند إرسال طلب GET!" + e);
printStackTrace();
}
// استخدم أخيرًا لإغلاق دفق الإدخال
أخيراً {
يحاول {
إذا (في != فارغة) {
in. Close();
}
} قبض (استثناء e2) {
e2.printStackTrace();
}
}
نتيجة الإرجاع؛
}
// احصل على جميع محتويات Zhihu الموصى بها من قبل المحررين
ArrayList ثابت<Zhihu> GetRecommendations(String content) {
// حدد قائمة ArrayList مسبقًا لتخزين النتائج
ArrayList<Zhihu> results = new ArrayList<Zhihu>();
// يُستخدم لمطابقة عنوان url، وهو رابط السؤال
نمط النمط = نمط
.compile("<h2>.+?question_link.+?href=/"(.+?)/".+?</h2>");
Matcher matcher = Pattern.matcher(content);
// ما إذا كان هناك كائن مطابق ناجح
Boolean isFind = matcher.find();
بينما (isFind) {
// حدد كائن Zhihu لتخزين المعلومات الملتقطة
Zhihu zhihuTemp = new Zhihu(matcher.group(1));
// أضف نتائج مطابقة ناجحة
results.add(zhihuTemp);
// استمر في العثور على الكائن المطابق التالي
isFind = matcher.find();
}
نتائج العودة؛
}
}
main.java
import java.util.ArrayList;
الطبقة العامة الرئيسية {
public static void main(String[] args) {
// تحديد الرابط المراد زيارته
عنوان URL للسلسلة = "http://www.zhihu.com/explore/recommendations";
// قم بالوصول إلى الرابط والحصول على محتوى الصفحة
محتوى السلسلة = Spider.SendGet(url);
// احصل على توصيات المحرر
ArrayList<Zhihu> myZhihu = Spider.GetRecommendations(content);
// طباعة النتائج
System.out.println(myZhihu);
}
}
ما ورد أعلاه هو السجل الكامل للحصول على إجابات Zhihu وهو مفصل للغاية ويمكن للأصدقاء المحتاجين الرجوع إليه.