Tớ tìm ra cách cào được 1M+ bài viết từ VnExpress, cậu thì sao?
Trong đợt thực tập này, nhiệm vụ đầu tiên của tớ là cào ra đủ 1M+ post từ VnExpress. Nhiệm vụ tân thủ mà. Tớ đã ngây thơ, và ngạo mạn nghĩ rằng chỉ cần lần dò thì có thể dễ dàng có đủ 1M+ đường dẫn để cào. Nhưng đời không như mơ, tớ ăn ban, tớ chỉ được 7k6 link với cách cũ mặc dù thử đủ loại chiến thuật. Rồi cuối cùng, nhờ người bạn ChatGPT, tớ đã tìm ra hướng xử lý hahahaha.
Bài viết này sẽ mô tả lại toàn bộ quá trình tớ tìm ra cách cào bài (mà tớ nghĩ là) siêu thông minh này, từ việc tuyệt vọng thử hết mọi cách trước khi đầu hàng, rồi có được khoảnh-khắc-aha nhờ uniform sampling.
Nào, bắt đầu thôi.
Đề bài từ sếp
Sếp: Anh khoán đề bài cho các em cào được 1M+ bài từ VnExpress. Xong bước này thì ta tiến hành các bước tiếp theo. Anh gợi ý là các em có thể dò vào từng link để tìm các link liên quan.
Tớ: Xời, đơn giản, em sẽ nhảy vào sitemap.xml
Sếp: Em cứ làm đi, mọi thứ cần có số liệu.
Cái đầu tự ngạo của tớ nghĩ rằng chỉ cần ChatGPT thì tớ có thể dễ dàng đạt mục tiêu thôi. Không. Tớ là đồ ngu.
Phân tích bài toán và chiến lược đầu tiên
Để có được 1M+ bài, thì ta phải tìm được 1M+ link. Để có cái link đó thì tớ bới sitemap.xml nhứ tớ có bảo sếp. Web nào lớn mà chả phải có cái này.
Các cậu nhìn thấy phần này chắc là sẽ lạc quan đầy niềm tin lắm ha, trúng mánh ha:
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://vnexpress.net/categories-sitemap.xml</loc>
<lastmod>2025-04-13T04:45:12+07:00</lastmod>
</sitemap>
<sitemap>
<loc>https://vnexpress.net/google-news-sitemap.xml</loc>
<lastmod>2025-04-13T04:45:12+07:00</lastmod>
</sitemap>
<sitemap>
<loc>https://vnexpress.net/latestnews-sitemap.xml</loc>
<lastmod>2025-04-13T04:45:12+07:00</lastmod>
</sitemap>
<sitemap>
<loc>https://vnexpress.net/articles-2025-sitemap.xml</loc>
<lastmod>2025-04-13T04:45:12+07:00</lastmod>
</sitemap>
<sitemap>
<loc>https://vnexpress.net/articles-2024-sitemap.xml</loc>
<lastmod>2025-04-13T04:45:12+07:00</lastmod>
</sitemap>
<sitemap>
<loc>https://vnexpress.net/articles-2023-sitemap.xml</loc>
<lastmod>2025-04-13T04:45:12+07:00</lastmod>
</sitemap>
<sitemap>
<loc>https://vnexpress.net/articles-2022-sitemap.xml</loc>
<lastmod>2025-04-13T04:45:12+07:00</lastmod>
</sitemap>
<sitemap>
<loc>https://vnexpress.net/articles-2021-sitemap.xml</loc>
<lastmod>2025-04-13T04:45:12+07:00</lastmod>
</sitemap>
</sitemapindex>
Biết gì không, thử truy cập vào là bị redirect về trang chủ. Bẩn bựa vô cùng. Liệu đây có phải là 1 cái honeytrap?
VnExpress chơi đẹp mặt tiền, nhưng khóa sạch cổng sau. Không crawl được.
Không bỏ cuộc, tớ thử đóng giả làm bot Google dùng User Agent. Làm gì có chuyện nó giấu không cho Google biết chứ, đúng không, SEO là cái sống còn của 1 trang tin tức mà. Đoán xem kết quả như thế nào. Haha, vẫn tạch lô, vẫn bị redirect.
Nhìn chung là tạch lô phát đầu. Không sao cả, mình có thể làm nông dân, tự tin giảm xuống 70%.
Nông dân trâu cày: Quét khắp trang lấy số
Tớ nghĩ đến vụ này khi thử navigation loanh quanh như gợi ý của sếp: Đâm sâu. Thử mấy cái chuyên mục xem sao nhỉ? Chà, thật bất ngờ. Mỗi khi navigate, nó sẽ đội lên 1 số, và tiếp tục đến khi redirect về https://timkiem.vnexpress.net/. Đại khái, cái link sẽ như thế này:
https://vnexpress.net/thoi-su/chinh-tri-p{i}
Cứ vậy mà dò i đến khi không được nữa, tức là đã hết bài trong mục. Như vậy, chỉ cần dò theo từng mục là ngon ăn rồi.
Có vẻ là có tiềm năng đấy, triển khai thôi. Game dễ nhỉ?
Không. Kết quả là 7k6 link, chính xác là 7638. So với 1M, thì đúng là con muỗi. Với 7k6 link này, tớ chỉ có được các bài từ 26/12/2024 đến 13/04/2025. Còn xa mới đủ. Được có 3 tháng thì làm ăn được cái trò trống gì chứ?
À đúng rồi, tiện đây nói luôn: newspaper4k không cào ra được ngày tháng viết bài của VnExpress, thông tin đấy phải tìm ở tag meta.
Cook luôn. Tớ ngồi thở dài ôm đầu.
Con khỉ tìm ra gà rán KFC
Tuyệt vọng lắm rồi đấy. Tớ bảo với sếp là, ôi anh ơi hay là mình lấy bài từ Dân Trí, có sẵn xml đẹp xinh chỉ việc ngồi chấm mút.
Sếp: Như vậy là lạc quan đó, tiến thêm được ~30x rồi. 👍 Chỉ cần x8 số đấy nữa là đến đích rồi, tiếp tục nhé.
Tớ: Để em thử đổi nguồn khác xem sao ạ, em vừa kiểm tra nhanh thì Dân Trí có sitemap đủ từ 2005 đến giờ có vẻ lạc quan hơn
Sếp: Nghĩa là thay vì ta về đích thì chọn cách dễ hơn là… đi về đích khác à? Tiếp cận kiểu này thì có cách dễ hơn nữa. Lên tải luôn bộ wiki data về, nó có sẵn hơn trăm triệu bài. Cần dữ liệu dạng đó thì có thể lên đây tải để dùng nhé. Không có vấn đề gì. Nhưng tập trung bài toán hiện tại, cái này có thể dùng sau.
Ơ cay thật, tức là có cách hay hơn? Tham vọng trong tớ bùng lên, và tớ hỏi ChatGPT xem là với 2 chiến thuật tớ đã xài thì có cách nào tiếp không. Nó gợi ý cho 3 chiến thuật: 1 là lấy sitemap bằng request thuần không qua trình duyệt, 2 là lật tung Wayback Machine lên.
Tớ chú ý đến cái chiến thuật số 3 hơn cả. Nó bảo là, mày thử xem cái ID phía cuối xem, có thể có bất ngờ.
Đây, ví dụ 1 bài viết sẽ có link như thế này:
https://vnexpress.net/thong-qua-du-thao-phuong-huong-nhan-su-trung-uong-khoa-14-4873218.html
Thấy số 4873218 chứ? Tớ quyết định thử giữ nguyên số đó, và đổi phần slug đằng trước. Link đó thành như thế này:
https://vnexpress.net/bombarido-crocodio-4873218.html
Voila! Nó redirect về link cũ 🤯 Xong tớ đổi số đi, lùi về tầm vài chục. Ra bài viết khác mới toanh. Khoảnh khắc a-ha tới rồi
Hóa ra là chỉ cần đúng ID (7 chữ số), slug là rác cũng được.
Đến lúc toán học được xài vào đây
Trong quá trình test, tớ có thử nghiên cứu quy luật. 2 số đầu sẽ quyết định năm đăng bài, ví dụ 48 sẽ là 2024-2025, 47 sẽ là 2024-2023. Tớ nhớ lại đoạn xml kia, năm bắt đầu là 2001. Thử trừ đi xem sao. Ồ không, nó lại là năm 2006, tức là có thể lùi xuống nữa. Lùi tới lùi hồi, xuống đến 18 thì thực sự là 2001.
Xong tớ phát hiện ra tiếp, là không phải cứ lùi thẳng là sẽ có bài. Giữa những khoảng ngẫu nhiên, nó cho 1 vố toàn ra 404. Hay lắm, thách đố trí thông minh của ta. Nếu giờ cứ cào chay cho lùi từ 4 triệu về 1 triệu thì căng nhỉ, vạn năm mới fetch xong được.
Tớ chợt nhớ ra sếp bảo là: Mình là kỹ sư, không cần đủ, chỉ cần đúng. Nhẩm lúc nãy ngồi test thì ước chừng có khoảng 70% là sẽ có bài. Voila, tớ có thể sử dụng xác suất ở đây.
Vậy là tớ hỏi ChatGPT là bây giờ có chiến lược nào để đạt được khoảng 95-98% số lượng không, chấp nhận vài % rơi rớt. Thừa dư 1M, chả lo, có gì điều chỉnh lên sau.
Nó tư vấn cho ngay: Bây giờ mày chặt ra thành đoạn nhỏ, lấy hẳn theo block 10k đi, rồi tiến hành sampling 1 vài mẫu thôi. Xong tớ hỏi tiếp là giờ lấy sample ra sao ní? Nó bèn cung cấp cho 1 công thức tính số sample trên quần thể hữu hạn (finite population), với 4 tham số là N - kích thước tổng thể, Z - độ tin cậy, e - sai số, p - tỷ lệ kỳ vọng bài hợp lệ:
Trong tình huống này, ta cho rằng p = 0.5 do chưa biết là có bao nhiêu hợp lệ, vậy cứ giả định là 50%. Vậy ta sẽ có các số cần thay
- (cho 95% độ tin cậy)
Thay số, ta có
Vậy với , muốn 95% confident và sai số 5%, cần lấy ~370 mẫu.
Vậy chỉ cần lấy khoảng 370 ID random đều trong tập để ước lượng tỷ lệ bài hợp lệ với sai số ±5%.
Mút chỉ chưa. Nếu tăng sai số lên ±8% thì chỉ cần khoảng 150 mẫu thôi. Nhưng mà thôi, chúng ta phải khó tính lên chứ. 300 mẫu cũng khá mút chỉ rồi.
Sau đó, ta tính tỷ lệ số bài fetch được trong block với số sample. Coi như với giả thiết mình đặt ra ban đầu là tồn tại khoảng 70% bài, như vậy tỷ lệ mà trên mốc 70% thì mình quét bằng hết.
Còn trên 40%? Cào ngẫu nhiên một nửa số ID. Trên 15%? Lấy 1/10. Bần cùng bất đắc dĩ thì quét 1 2 bài lấy lệ rồi té. Cái nào dính 404 thì cache lại kiểm tra.
Thấy không, siêu thông minh.