LƯU Ý LỚN

Mục đích tạo ra tool này là để luyện code web, code PHP và MySQL khi xử lý web scraping kết hợp thư viện Simple HTML DOM Parser.

============================================================================

Đầu tiên, hãy đọc bài viết này trước để hiểu nội dung bài viết này sẽ nói gì:

https://minhthuongeh.wordpress.com/2019/04/29/jav-model-search-tool-tu-y-tuong-toi-hien-thuc-hoa-ung-dung

Hiện tại, công cụ đã được cập nhật tính năng tự động gợi ý kết quả liên quan. Đại ý là giống với cách thức gợi ý kết quả của các công cụ tìm kiếm hiện tại. Khi bạn gõ vào từ khóa, công cụ sẽ tự động gợi ý các kết quả có khả năng liên quan.

Bài viết này sẽ tóm tắt cách tôi giải quyết vấn đề này. Thật ra cũng không có gì cao siêu lắm.

h8T83X1

Để đơn giản thì bài viết này tôi sẽ hạn chế chèn code vào. Tôi chỉ tập trung nói về hướng suy nghĩ của tôi để giải quyết vấn đề chính thôi.

Mục tiêu

Khắc phục lỗi trong trường hợp không tìm thấy model có tên do người dùng nhập vào.

Lấy ra danh sách của toàn bộ model hiện đang có trên website database.

Xử lý autocomplete cho khung nhập tên model của công cụ.

Hướng giải quyết

Về vụ xử lý khi không tìm thấy model do người dùng nhập vào thì khá dễ. Quan sát trang báo lỗi của trang web cơ sở dữ liệu đích, tôi biết được khi không tìm thấy một model nào đó, nó sẽ trả về trang báo lỗi siêu kinh điển là “404 NOT FOUND”.

huong-dan-viet-jav-search-tool-8.jpg

Viết loạt bài cho công cụ này thật sự rất mệt mỏi. Phải liên tục mở Photoshop để làm mờ đi hình ảnh không liên quan…

thobua_11 (1)

Quan sát cấu trúc thẻ HTML của trang báo lỗi này, tôi biết được nó sẽ đặt dòng thông báo lỗi trong thẻ <h1> có class với tên cụ thể.

huong-dan-viet-jav-search-tool-9-1.jpg

Như vậy, tôi sẽ triển theo hướng như sau: Cứ với mỗi tên model do người dùng nhập vào, tôi sẽ vẫn cho truy vấn tới trang web chứa database. Nhưng đầu tiên phải check xem có tồn tại thẻ <h1> với class tương ứng không. Sau đó nếu thẻ này tồn tại kèm theo innertext của nó là “404 Not Found” thì dừng, báo lỗi ngay. Nếu không trùng với các điều kiện trên thì cho xử lý tiếp.

7

Tiếp theo là câu chuyện làm sao để có thể lấy ra toàn bộ tên của các model hiện đang có trên database của website. Cách tôi xử lý chỗ này hơi buồn cười và thô một chút.

Tôi quan sát thấy trang web trả về tổng cộng 125 trang kết quả, với lần lượt mỗi trang sẽ hiển thị 10 model. Như vậy làm sao để code có thể tự động xác định có tổng cộng bao nhiêu page? Bước này cần thiết bởi vì phải biết số page để vòng lặp có thể tự động request liên tục vào các trang đó và lấy kết quả trong từng trang về và lưu vào mảng.

Tôi thấy chỗ button cho người dùng bấm vào từng trang sẽ nằm trong một <ul> có class cụ thể. Vậy thì tôi sẽ cho tool request tới trang đầu tiên, sau đó tìm tới <ul> vừa nói ở trên.

Tiếp theo, ta xác định số trang tổng bằng cách nhìn vào các dòng <li> trong hình.

huong-dan-viet-jav-search-tool-10.jpg

Trang cuối cùng sẽ có số thứ tự là 125. Như vậy thẻ <li> thứ 6 sẽ là thẻ cần lấy ra con số này. Nhưng bạn phải lưu ý một điều: trong lập trình thì việc đếm bao giờ cũng đi từ 0. Như vậy thẻ cần lấy ra trong trường hợp này là thẻ <li> thứ 5.

$page2 = $page1->find(‘li’,5);

Tiếp theo, ta thấy trong thẻ <li> này, số 125 được đặt trong thẻ anchor <a>. Do đó, phải truy vấn tìm kiếm thêm một lần nữa nhằm lấy ra được innertext của nó.

$page3 = $page2->find(‘a’,0)->innertext;

Để cẩn thận, ta nên xử lý innertext này thành dạng số. Có một cách nhanh chóng để chuyển đổi từ chuỗi sang số là dùng ép kiểu: ((int) $page3). Rất đơn giản!

45

Sau cùng, ý tưởng chính chỗ này sẽ là cho duyệt toàn bộ các trang từ trang đầu cho tới trang cuối cùng. Trang cuối cùng chính là giá trị biến $page3 mà ta vừa lấy ra được. Như vậy tôi sẽ cho chạy vòng for() với giá trị $i bên trong chạy từ 1. Vì mỗi lần chạy, công cụ sẽ truy xuất tới URL của website đích kèm giá trị biến $i. Mà trang web thì đánh trang từ 1. Do đó, ta không thể cho chạy for() từ giá trị $i=0 được. Mà nếu đã cho chạy $i từ 1 thì lưu ý khi xét điều kiện cho $i phải là so sánh “<=” mới đúng.

Tới đây bắt đầu rối thêm đây.

huong-dan-viet-jav-search-tool-11.jpg

Tôi nhận thấy với 10 kết quả cho mỗi page của website đích, ta sẽ có 10 dòng tên. Mục tiêu của tôi là cần lấy ra 10 cái name cho mỗi page. Quan sát thấy mỗi cái name sẽ được đặt trong một thẻ <h3> với class cụ thể. Bên trong nó lại là thẻ anchor <a>. Mỗi page sẽ có 10 thẻ <h3> với class giống nhau như vậy. Trừ trang cuối cùng thì số lượng có thể ít hơn 10 model. Nhưng đó không phải vấn đề cần quan tâm.

Bây giờ tôi sẽ cần khai báo một mảng array() trước. Sau đó tôi cho chạy vòng for() duyệt qua toàn bộ 125 trang kết quả. Trong mỗi trang, tôi sẽ cần phải cho tool đẩy 1 luồng HTTP request tới website đích với giá trị trang là biến $i.

Trong mỗi trang như vậy, tôi cho chạy foreach() để duyệt qua toàn bộ các thẻ <h3> ta vừa nói ở trên. Tiếp tục, trong mỗi thẻ <h3> với class cụ thể đó, tôi lại cho tìm ra thẻ anchor <a> bên trong nó và lấy ra giá trị innertext và cho nó vào mảng.

Sau cùng, vì function javascript mà tôi dùng để xử lý vụ autocomplete cho khung input của người dùng cần phải đặt các biến trong mảng theo dạng:

var modelName = [“abc”, “defg”];

Do đó để tiện cho việc xử lý, với hơn 1000 cái tên thì không thể nào tôi đi tìm từng cái rồi thêm dấu ” vào trước vào sau mỗi tên được. Do đó khi xử lý lấy innertext của thẻ anchor trong <h3> trên, tôi cho thêm vào dấu ” trước và sau mỗi tên khi bỏ giá trị vào mảng.

$items[] = ‘”‘.$a->innertext.'”‘;

Đồng thời, tôi xử lý thêm dấu phẩy giữa các tên bằng câu lệnh:

$string=implode(“,”,$items);

Như vậy là tôi đã có được tập dữ liệu đầy đủ tên các model hiện có trên database của website đích.

Việc sau cùng là xây dựng hàm autocomplete cho khung input. May mắn là tôi tìm thấy một đoạn code mẫu minh họa cho vấn đề này (hoàn toàn miễn phí).

Tới đây thì tôi chỉ việc cho chạy và chờ tầm 4 -> 5 phút để tool có thể tổng hợp tên của toàn bộ các model hiện có.

Lưu ý là nếu bạn sử dụng XAMPP giống tôi để chạy code PHP local trước, thì hãy vào file php.ini và chuyển đổi giá trị max_execution_time=0 thay vì 30 như mặc định. Có như vậy thì code thực thi chạy lúc lấy tên trên 125 page không bị gián đoạn.

Sau cùng, kết hợp autocomplete code vào tool hiện tại, bây giờ khi tôi gõ tên một model bất kỳ có trong database của tool tôi, thì nó sẽ hiển thị gợi ý và bạn có thể bấm chuột trực tiếp vào gợi ý đó để tool tìm và hiển thị kết quả.

4

huong-dan-viet-jav-search-tool-12.jpg

Bạn có thể xem video minh họa tại đây:

Thế là xong được các vấn đề đơn giản trước.

Thật ra chỗ này vẫn còn rất nhiều điểm dở và điểm cần cải tiến. Điểm dở đầu tiên và dễ thấy nhất chính là ở khâu xử lý lấy tên toàn bộ model. Nếu làm như thế này thì có nghĩa là mỗi lần có cập nhật thêm name mới, tôi lại phải cho chạy code riêng để collect, sau đó mở code của tool ra và tìm tới function() autocomplete và đổ thêm tên vào. Cực kỳ bất tiện.

Thêm nữa, mọi dữ liệu mỗi lần tìm kiếm không hề được lưu lại trên database nào của tool. Điều này dẫn đến việc làm chậm khả năng truy xuất nếu cứ đẩy luồng request qua cho website chứa database. Nếu một model được tìm nhiều thì chẳng khác nào ta cứ phải liên tục truy vấn? Rất bất tiện. Triển khai một database để lưu trữ dần dần trên chính máy chủ của tool sẽ là giải pháp cực kỳ hoàn hảo.