تحدثنا في الحلقة الأخيرة عن ضرورة استخدام Java لإنشاء زاحف Zhihu، لذلك سندرس هذه المرة كيفية استخدام الكود للحصول على محتوى صفحة الويب.
أولاً، إذا لم تكن لديك خبرة في HTML وCSS وJS وAJAX، فمن المستحسن الانتقال إلى W3C (انقر فوقي، انقر فوقي) لتتعلم القليل.
عند الحديث عن HTML، يتضمن هذا مشكلة الوصول إلى GET والوصول إلى POST.
إذا كنت تفتقر إلى فهم هذا الجانب، يمكنك قراءة هذه المقالة من W3C: "GET vs. POST".
اها، لن أخوض في التفاصيل هنا.
بعد ذلك، نحتاج بعد ذلك إلى استخدام Java للزحف إلى محتوى صفحة الويب.
في هذا الوقت، سيكون بايدو الخاص بنا مفيدًا.
هذا صحيح، فهو لم يعد اختبار سرعة الإنترنت المجهول، بل على وشك أن يصبح خنزير غينيا الزواحف لدينا! ~
دعونا نلقي نظرة على صفحة بايدو الرئيسية أولاً:
أعتقد أن الجميع يعلم أن صفحة مثل هذه هي نتيجة العمل المشترك بين HTML وCSS.
ننقر بزر الماوس الأيمن على الصفحة في المتصفح ونختار "عرض كود مصدر الصفحة":
هذا صحيح، إنه شيء من هذا القبيل. هذا هو الكود المصدري لصفحة بايدو.
مهمتنا التالية هي استخدام الزاحف الخاص بنا للحصول على نفس الشيء.
دعونا نلقي نظرة أولاً على كود المصدر البسيط:
استيراد java.io.*;
استيراد java.net.*;
الطبقة العامة الرئيسية {
public static void main(String[] args) {
// تحديد الرابط المراد زيارته
عنوان URL للسلسلة = "http://www.baidu.com";
// تحديد سلسلة لتخزين محتوى صفحة الويب
نتيجة السلسلة = ""؛
// تحديد دفق إدخال الأحرف المخزنة مؤقتًا
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();
}
}
System.out.println(result);
}
}
ما ورد أعلاه هو محاكاة Java للوصول إلى طريقة Baidu الرئيسية.
يمكنك تشغيله لمعرفة النتائج:
آها، إنه بالضبط نفس ما رأيناه في المتصفح سابقًا. عند هذه النقطة، أبسط الزاحف جاهز.
لكن مثل هذه الكومة الكبيرة من الأشياء قد لا تكون جميعها ما أريده، فكيف يمكنني الحصول على ما أريد منه؟
خذ شعار بايدو الكبير كمثال.
الاحتياجات المؤقتة:
احصل على رابط الصورة للمخلب الكبير لشعار بايدو.
لنتحدث أولاً عن طريقة عرض المتصفح.
انقر بزر الماوس الأيمن على الصورة وحدد Inspect Elements (يحتوي كل من Firefox وGoogle وIE11 على هذه الوظيفة، لكن الأسماء مختلفة):
آها، يمكنك رؤية علامة img الفقيرة محاطة بالكثير من عناصر div.
هذا src هو الرابط للصورة.
فكيف نفعل ذلك في جافا؟
يرجى ملاحظة أنه من أجل تسهيل عرض التعليمات البرمجية، لم يتم تغليف جميع الرموز حسب الفئات، يرجى فهم ذلك.
لنقم أولاً بتغليف الكود السابق في دالة sendGet:
استيراد java.io.*;
استيراد java.net.*;
الطبقة العامة الرئيسية {
سلسلة ثابتة sendGet(سلسلة رابط) {
// تحديد سلسلة لتخزين محتوى صفحة الويب
نتيجة السلسلة = ""؛
// تحديد دفق إدخال الأحرف المخزنة مؤقتًا
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();
}
}
نتيجة الإرجاع؛
}
public static void main(String[] args) {
// تحديد الرابط المراد زيارته
عنوان URL للسلسلة = "http://www.baidu.com";
// قم بالوصول إلى الرابط والحصول على محتوى الصفحة
نتيجة السلسلة = sendGet(url);
System.out.println(result);
}
}
يبدو هذا أكثر ترتيبًا، من فضلك اغفر لي اضطراب الوسواس القهري.
المهمة التالية هي العثور على رابط الصورة من بين العديد من الأشياء التي تم الحصول عليها.
الطريقة الأولى التي يمكننا التفكير بها هي استخدام وظيفة فهرس البحث عن سلاسل فرعية في نتيجة السلسلة للكود المصدر للصفحة.
نعم، يمكن لهذه الطريقة حل هذه المشكلة ببطء، مثل IndexOf("src") مباشرة للعثور على الرقم التسلسلي للبدء، ثم الحصول على الرقم التسلسلي النهائي بسرعة.
ومع ذلك، لا يمكننا دائمًا استخدام هذه الطريقة، فصنادل القش مناسبة فقط للتجول، وفي وقت لاحق، ما زلنا بحاجة إلى قطع الأرجل الاصطناعية لتثبيت الرؤوس.
أرجو أن تغفري تطفلي وتستمري.
إذن كيف نجد src لهذه الصورة؟
هذا صحيح، كما قال الجمهور أدناه، المطابقة المنتظمة.
إذا لم يكن أي من الطلاب متأكدًا من التعبيرات العادية، فيمكنك الرجوع إلى هذه المقالة: [Python] Web Crawler (7): البرنامج التعليمي للتعبيرات العادية في Python.
ببساطة، التعبير العادي يشبه المطابقة.
على سبيل المثال، يقف هنا ثلاثة رجال بدينين، يرتدون ملابس حمراء، وملابس زرقاء، وملابس خضراء.
القاعدة هي: أمسك بالشخص الذي يرتدي اللون الأخضر!
ثم أمسك بالرجل الأخضر السمين وحده.
الأمر بهذه البساطة.
ومع ذلك، فإن القواعد النحوية العادية لا تزال واسعة النطاق وعميقة، ومن المحتم أن تشعر بالارتباك قليلاً عند التعامل معها لأول مرة.
أوصي بأداة اختبار منتظمة عبر الإنترنت للجميع: اختبار التعبير العادي عبر الإنترنت.
مع الانتظام كسلاح سحري، كيفية استخدام الانتظام في جافا؟
دعونا نلقي نظرة على البرقوق الصغير البسيط أولاً.
آه، خطأ، الكستناء الصغير.
// تحديد قالب النمط، باستخدام التعبيرات العادية، والمحتوى الذي سيتم التقاطه موجود بين قوسين
// إنه يعادل دفن فخ، وسوف يسقط إذا تطابق.
نمط النمط = Pattern.compile("href=/"(.+?)/"");
// تحديد المطابق للمطابقة
Matcher matcher = Pattern.matcher("<a href=/"index.html/">صفحتي الرئيسية</a>");
// إذا وجدت
إذا (matcher.find()) {
// اطبع النتيجة
System.out.println(matcher.group(1));
}
نتائج التشغيل:
Index.html
نعم، هذا هو الكود العادي الأول لدينا.
يجب أن يكون رابط التقاط الصور في هذا التطبيق في متناول يدك.
نقوم بتغليف المطابقة العادية في دالة، ثم نقوم بتعديل الكود كما يلي:
استيراد 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.baidu.com";
// قم بالوصول إلى الرابط والحصول على محتوى الصفحة
نتيجة السلسلة = SendGet(url);
// استخدم التعبيرات العادية لمطابقة محتوى الصورة
String imgSrc = RegexString(result, "القواعد النحوية العادية القادمة");
// طباعة النتائج
System.out.println(imgSrc);
}
}
حسنًا، الآن أصبح كل شيء جاهزًا، مجرد قواعد نحوية عادية!
إذن ما هو البيان العادي الأكثر ملاءمة؟
لقد وجدنا أنه طالما حصلنا على السلسلة src=xxxxxx، يمكننا الحصول على رابط src بأكمله.
إذن عبارة عادية بسيطة: src=/"(.+?)/"
الكود الكامل هو كما يلي:
استيراد 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.baidu.com";
// قم بالوصول إلى الرابط والحصول على محتوى الصفحة
نتيجة السلسلة = SendGet(url);
// استخدم التعبيرات العادية لمطابقة محتوى الصورة
String imgSrc = RegexString(result, "src=/"(.+?)/"");
// طباعة النتائج
System.out.println(imgSrc);
}
}
بهذه الطريقة، يمكننا استخدام جافا للحصول على الرابط إلى شعار بايدو.
حسنًا، على الرغم من أنني أمضيت الكثير من الوقت في الحديث عن بايدو، إلا أنه يجب وضع الأساس بقوة في المرة القادمة التي سنبدأ فيها رسميًا بالتركيز على Zhihu! ~