Zhihu هو مجتمع أسئلة وأجوبة حقيقي عبر الإنترنت يتمتع بجو مجتمعي ودود وعقلاني وجاد يربط النخب من جميع مناحي الحياة. إنهم يتشاركون المعرفة والخبرة والرؤى المهنية لبعضهم البعض، ويقدمون باستمرار معلومات عالية الجودة للإنترنت الصيني.
أولاً، اقضي من ثلاث إلى خمس دقائق في تصميم شعار =. =باعتباري مبرمجًا، كان لدي دائمًا قلب لكوني فنانًا!
حسنًا، إنه مؤقت قليلاً، لذا سأكتفي به الآن.
بعد ذلك، بدأنا في صنع زاحف Zhihu.
أولاً، حدد الهدف الأول: توصية المحرر.
رابط الويب: http://www.zhihu.com/explore/recommendations
قمنا بتعديل الكود الأخير بشكل طفيف لتحقيق القدرة على الحصول على محتوى الصفحة أولاً:
استيراد java.io.*;
استيراد java.net.*;
import java.util.regex.*;
الطبقة العامة الرئيسية {
سلسلة ثابتة 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()));
// يُستخدم لتخزين بيانات كل صف تم التقاطه مؤقتًا
خط السلسلة؛
بينما ((line = in.readLine()) != null) {
// اجتياز كل صف تم التقاطه وتخزينه في النتيجة
النتيجة += السطر؛
}
} قبض (الاستثناء ه) {
System.out.println("حدث استثناء عند إرسال طلب GET!" + e);
printStackTrace();
}
// استخدم أخيرًا لإغلاق دفق الإدخال
أخيراً {
يحاول {
إذا (في != فارغة) {
in. Close();
}
} قبض (استثناء e2) {
e2.printStackTrace();
}
}
نتيجة الإرجاع؛
}
سلسلة ثابتة RegexString(String targetStr, String PatternStr) {
// تحديد قالب النمط، باستخدام التعبيرات العادية، والمحتوى الذي سيتم التقاطه موجود بين قوسين
// إنه يعادل دفن فخ، وسوف يسقط إذا تطابق.
نمط النمط = Pattern.compile(patternStr);
// تحديد المطابق للمطابقة
Matcher matcher = Pattern.matcher(targetStr);
// إذا وجدت
إذا (matcher.find()) {
// اطبع النتيجة
إرجاع matcher.group(1);
}
إرجاع "لا شيء" ؛
}
public static void main(String[] args) {
// تحديد الرابط المراد زيارته
عنوان URL للسلسلة = "http://www.zhihu.com/explore/recommendations";
// قم بالوصول إلى الرابط والحصول على محتوى الصفحة
نتيجة السلسلة = SendGet(url);
// استخدم التعبيرات العادية لمطابقة محتوى الصورة
//String imgSrc = RegexString(result, "src=/"(.+?)/"");
// طباعة النتائج
System.out.println(result);
}
}
لا توجد مشكلة بعد تشغيله، والخطوة التالية هي مشكلة المطابقة العادية.
أولاً، دعونا نتلقى جميع الأسئلة في هذه الصفحة.
انقر بزر الماوس الأيمن على العنوان وافحص العنصر:
اها، يمكنك أن ترى أن العنوان هو في الواقع علامة، وهو ارتباط تشعبي، والشيء الذي يمكن تمييزه عن الارتباطات التشعبية الأخرى يجب أن يكون الفئة، وهو محدد الفئة.
لذلك يخرج بياننا المعتاد: question_link.+?href=/"(.+?)/"
استدعاء وظيفة RegexString وتمرير المعلمات:
public static void main(String[] args) {
// تحديد الرابط المراد زيارته
عنوان URL للسلسلة = "http://www.zhihu.com/explore/recommendations";
// قم بالوصول إلى الرابط والحصول على محتوى الصفحة
نتيجة السلسلة = SendGet(url);
// استخدم التعبيرات العادية لمطابقة محتوى الصورة
String imgSrc = RegexString(result, "question_link.+?>(.+?)<");
// طباعة النتائج
System.out.println(imgSrc);
}
آه، يمكنك أن ترى أننا نجحنا في الحصول على عنوان (ملاحظة، عنوان واحد فقط):
إنتظر لحظة، ما كل هذه الفوضى؟ !
لا تتوتر=. =إنها مجرد أحرف مشوهة.
بالنسبة لمشاكل الترميز، يرجى الاطلاع على: مجموعة أحرف HTML
بشكل عام، الترميزات السائدة التي تتمتع بدعم أفضل للغة الصينية هي ترميز UTF-8 وGB2312 وGBK.
يمكن لصفحة الويب ضبط ترميز صفحة الويب من خلال مجموعة أحرف العلامة الوصفية، على سبيل المثال:
<meta charset="utf-8" />
دعنا ننقر بزر الماوس الأيمن لعرض كود مصدر الصفحة:
كما ترون، يستخدم Zhihu ترميز UTF-8.
هنا سأشرح لك الفرق بين عرض الكود المصدري للصفحة وفحص العناصر.
يعرض عرض الكود المصدري للصفحة جميع الأكواد البرمجية للصفحة بأكملها، ولا يتم تنسيقه وفقًا لعلامات HTML، وهو ما يعادل عرض الكود المصدري مباشرةً. وهذه الطريقة أكثر فائدة لعرض معلومات صفحة الويب بأكملها، مثل ميتا.
فحص العنصر، أو تسميه بعض المتصفحات عنصر العرض، وهو عرض العنصر الذي تنقر عليه بزر الماوس الأيمن، مثل div أو img، وهو أكثر ملاءمة لعرض سمات وعلامات الكائن بشكل فردي.
حسنًا، الآن نعلم أن المشكلة تكمن في التشفير، والخطوة التالية هي تحويل تشفير المحتوى الذي تم التقاطه.
التنفيذ في جافا بسيط للغاية، ما عليك سوى تحديد طريقة التشفير في InputStreamReader:
// تهيئة دفق إدخال BufferedReader لقراءة استجابة عنوان URL
in = new BufferedReader(new InputStreamReader(
Connection.getInputStream()"UTF-8"));
إذا قمت بتشغيل البرنامج مرة أخرى في هذا الوقت، ستجد أنه يمكن عرض العنوان بشكل طبيعي:
نعم! جيد جدًا!
ولكن الآن هناك عنوان واحد فقط، ونحن بحاجة إلى جميع الألقاب.
نقوم بتعديل التعبير العادي قليلاً ونخزن نتائج البحث في قائمة ArrayList:
استيراد java.io.*;
استيراد java.net.*;
import java.util.ArrayList;
import java.util.regex.*;
الطبقة العامة الرئيسية {
سلسلة ثابتة 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();
}
}
نتيجة الإرجاع؛
}
static ArrayList<String> RegexString(String targetStr, String PatternStr) {
// حدد قائمة ArrayList مسبقًا لتخزين النتائج
ArrayList<String> results = new ArrayList<String>();
// تحديد قالب النمط، باستخدام التعبيرات العادية، والمحتوى الذي سيتم التقاطه موجود بين قوسين
نمط النمط = Pattern.compile(patternStr);
// تحديد المطابق للمطابقة
Matcher matcher = Pattern.matcher(targetStr);
// إذا وجدت
boolean isFind = matcher.find();
// استخدم حلقة للعثور على كل كلفن في الجملة واستبداله وإضافة المحتوى إلى sb
بينما (isFind) {
// أضف نتائج مطابقة ناجحة
results.add(matcher.group(1));
// استمر في العثور على الكائن المطابق التالي
isFind = matcher.find();
}
نتائج العودة؛
}
public static void main(String[] args) {
// تحديد الرابط المراد زيارته
عنوان URL للسلسلة = "http://www.zhihu.com/explore/recommendations";
// قم بالوصول إلى الرابط والحصول على محتوى الصفحة
نتيجة السلسلة = SendGet(url);
// استخدم التعبيرات العادية لمطابقة محتوى الصورة
ArrayList<String> imgSrc = RegexString(result, "question_link.+?>(.+?)<");
// طباعة النتائج
System.out.println(imgSrc);
}
}
سيطابق هذا جميع النتائج (لأن قائمة ArrayList تتم طباعتها مباشرة، سيكون هناك بعض الأقواس المربعة والفواصل):
حسنًا، هذه هي الخطوة الأولى لزاحف Zhihu.
لكن يمكننا أن نرى أنه لا توجد طريقة لالتقاط جميع الأسئلة والأجوبة بهذه الطريقة.
نحتاج إلى تصميم فئة تغليف Zhihu لتخزين جميع الكائنات الملتقطة.
كود مصدر Zhihu.java:
import java.util.ArrayList;
الطبقة العامة Zhihu {
سؤال السلسلة العامة؛ // سؤال
public String zhihuUrl;// رابط صفحة الويب
إجابات ArrayList<String> العامة؛ // مصفوفة لتخزين جميع الإجابات
// يقوم المُنشئ بتهيئة البيانات
تشيهو العامة () {
سؤال = "";
zhihuUrl = "";
الإجابات = new ArrayList<String>();
}
@تجاوز
سلسلة عامة إلى سلسلة () {
إرجاع "السؤال:" + السؤال + "/nLink:" + zhihuUrl + "/nAnswer:" + الإجابات + "/n"؛
}
}
قم بإنشاء فئة Spider جديدة لتخزين بعض الوظائف الشائعة الاستخدام لبرامج الزحف.
كود مصدر 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();
}
}
نتيجة الإرجاع؛
}
ArrayList ثابت<Zhihu> GetZhihu(محتوى السلسلة) {
// حدد قائمة ArrayList مسبقًا لتخزين النتائج
ArrayList<Zhihu> results = new ArrayList<Zhihu>();
// يستخدم لمطابقة العناوين
Pattern questionPattern = Pattern.compile("question_link.+?>(.+?)<");
Matcher questionMatcher = questionPattern.matcher(content);
// يُستخدم لمطابقة عنوان url، وهو رابط السؤال
Pattern urlPattern = Pattern.compile("question_link.+?href=/"(.+?)/"");
Matcher urlMatcher = urlPattern.matcher(content);
// يجب أن يتطابق كل من السؤال والرابط
boolean isFind = questionMatcher.find() && urlMatcher.find();
بينما (isFind) {
// حدد كائن Zhihu لتخزين المعلومات الملتقطة
Zhihu zhuhuTemp = new Zhihu();
zhuhuTemp.question = questionMatcher.group(1);
zhuhuTemp.zhihuUrl = "http://www.zhihu.com" + urlMatcher.group(1);
// أضف نتائج مطابقة ناجحة
results.add(zhuhuTemp);
// استمر في العثور على الكائن المطابق التالي
isFind = questionMatcher.find() && urlMatcher.find();
}
نتائج العودة؛
}
}
الطريقة الرئيسية الأخيرة هي المسؤولة عن الاتصال.
import java.util.ArrayList;
الطبقة العامة الرئيسية {
public static void main(String[] args) {
// تحديد الرابط المراد زيارته
عنوان URL للسلسلة = "http://www.zhihu.com/explore/recommendations";
// قم بالوصول إلى الرابط والحصول على محتوى الصفحة
محتوى السلسلة = Spider.SendGet(url);
// احصل على كافة كائنات Zhihu في هذه الصفحة
ArrayList<Zhihu> myZhihu = Spider.GetZhihu(content);
// طباعة النتائج
System.out.println(myZhihu);
}
}
حسنًا، هذا كل شيء. قم بتشغيله وشاهد النتائج:
نتائج جيدة.
والخطوة التالية هي الوصول إلى الرابط والحصول على جميع الإجابات.
سوف نقدمه في المرة القادمة.
حسنًا، ما ورد أعلاه عبارة عن مقدمة موجزة للعملية الكاملة لكيفية استخدام Java لالتقاط المحتوى الذي أوصى به محررو Zhihu، وهو مفصل للغاية وسهل الفهم، ويمكن للأصدقاء المحتاجين الرجوع إليه والتوسع فيه بحرية