ในชุดทดสอบที่มองเห็นการรั่วไหลได้ชัดเจน goose3 ให้ content-token precision 1.0000 และไม่มีโทเคนปนเปื้อนแม้แต่ตัวเดียว ไม่มีคำจากเมนู โฆษณา แถบข้าง คอมเมนต์ หรือโปรโมชันหลุดเข้ามาในผลลัพธ์เลยสักคำเดียว ไม่มีเครื่องมือทั้งหกตัวไหนที่ทำได้เทียบเท่านี้
แต่อีกด้านหนึ่ง มันกลับมี article recall แย่ที่สุดในชุดทดสอบ — 0.8243 จากทั้งหมด 22 fixture เทียบกับ 1.0000 ของ Mozilla Readability — เพราะในสอง fixture มันส่งกลับมาเป็นสตริงว่าง
สองค่านี้เชื่อมกันด้วยกฎการให้คะแนน: ถ้าผลลัพธ์ว่าง ก็ไม่ช่วยอะไรกับ conditional precision ส่วน recall จะบันทึกไว้ตรง ๆ ว่ามีการพลาดเกิดขึ้น
goose3 คืออะไร
goose3 คือเวอร์ชันต่อยอดบน Python 3 ของสายพัฒนาที่เริ่มจาก Goose ของ Gravity Labs บน Scala และต่อด้วย python-goose มาก่อน มันเป็น ตัวสกัดบทความพร้อมเมตาดาตา ไม่ใช่เครื่องมือดึงข้อความดิบ: สร้าง Goose แล้วเรียก extract() คุณจะได้ออบเจ็กต์ Article ที่มีฟิลด์ให้ใช้งานราว 28 รายการ เช่น ข้อความที่ทำความสะอาดแล้ว, ชื่อบทความ, ผู้เขียน, วันที่เผยแพร่, รูปภาพหลัก, คำอธิบายเมตา, แท็ก, ลิงก์, ทวีต และอื่น ๆ
เอกสารอ้างอิงทางการ: ที่เก็บโค้ดอย่างเป็นทางการของ goose3.

เวอร์ชันที่ทดสอบ: 3.1.22, ใบอนุญาต Apache, ดาวบน GitHub 912 ดวง, push ล่าสุด 2026-07-23 — ยังมีการดูแลอยู่ในช่วงเวลาที่ทดสอบ Python 3.14.2
API ใช้แค่สองบรรทัดกับอีกหนึ่งข้อควรจำ:
from goose3 import Goose
g = Goose()
try:
article = g.extract(raw_html=html)
text = article.cleaned_text
finally:
g.close() # ควรปิดอย่างชัดเจนหลังใช้งาน
คำสั่ง close() ตรงนี้ควรเน้นไว้ เพราะลืมได้ง่ายและไม่มีอะไรเตือนคุณ บทความรีวิวนี้ไม่ได้รันการทดสอบแบบวนลูปเพื่อวัดเซสชัน การเชื่อมต่อ หรือหน่วยความจำคงค้างเมื่อไม่เรียกปิด ดังนั้นคำว่า “resource leak” จะเกินหลักฐานที่มีอยู่ ให้มองการปิดแบบชัดเจนเป็นข้อกำหนดด้าน lifecycle ตามที่การใช้งาน API แสดงไว้ตรงนี้
จุดแลกเปลี่ยนที่วัดได้
ตัวแยกข้อมูล 6 ตัว ชุด fixture ที่ติดป้ายกำกับไว้ 1 ชุด และตัวให้คะแนน 1 ตัว ทุกบล็อกในทุก fixture ถูกกำกับเป็น article หรือ boilerplate และมี sentinel token เฉพาะของตัวเอง ดังนั้นคำถามว่า “ดึงหน่วยนี้กลับมาได้ไหม” จึงวัดแบบตรงตัวจากการมีอยู่ของ substring ไม่ใช่คะแนนความคล้าย
| Library | Article recall (all 22) | Boilerplate leak | Content-token precision | Contaminating tokens | Produced output |
|---|---|---|---|---|---|
| Readability | 1.0000 | 0.2353 | 0.9109 | 35 | 22/22 |
| trafilatura | 0.9865 | 0.0588 | 0.9411 | 4 | 22/22 |
| newspaper4k | 0.9865 | 0.0000 | 0.9452 | 0 | 22/22 |
| resiliparse | 0.9054 | 0.0588 | 0.9381 | 7 | 22/22 |
| jusText | 0.8378 | 0.4706 | 0.8760 | 74 | 19/22 |
| goose3 | 0.8243 | 0.0000 | 1.0000 | 0 | 20/22 |
sixway-scores.json. ค่า recall คิดจากทั้ง 22 fixture ส่วน leak rate และ precision คิดจาก 11 fixture ที่มีทั้งหน่วย article และ boilerplate อยู่ด้วยกัน.
เวลาจะอ่านคอลัมน์ precision ให้ดูคอลัมน์สุดท้ายประกอบเสมอ เพราะ precision ตรงนี้คือ คำนวณเฉพาะกรณีที่มีผลลัพธ์ออกมา — ถ้าไลบรารีส่งสตริงว่างใน fixture ใด fixture หนึ่ง มันจะไม่ถูกนับทั้งในตัวเศษและตัวส่วนของค่าเฉลี่ย จึงทำให้การ “ไม่ตอบ” ดูไม่เสียอะไรในสูตรนี้ ตัวเศษคือการทับซ้อนแบบ multiset ระหว่าง non-stopword tokens ที่ดึงออกมากับ article tokens ที่ติดป้ายกำกับไว้ ส่วนตัวส่วนคือ non-stopword tokens ทั้งหมดที่ดึงมา คำว่า “contaminating tokens” แคบกว่านั้น: คือการทับซ้อนกับ boilerplate tokens ที่ติดป้ายกำกับไว้เท่านั้น token ที่ดึงมาแล้วไม่ตรงทั้ง article และ boilerplate จะทำให้ precision ลดลง แม้จะไม่เพิ่มจำนวน contaminating tokens ก็ตาม รวมถึงกรณี token ซ้ำเกินจำนวนใน multiset ของ article ด้วย นี่คือเหตุผลที่ newspaper4k อาจมี contaminating tokens = 0 แต่ precision ยังต่ำกว่า 1.0000 ได้ goose3 ได้ 1.0000 จาก 10 ใน 11 fixture; ส่วน Readability, trafilatura, newspaper4k และ resiliparse ถูกให้คะแนนครบ 11 จาก 11
ค่า 1.0000 นี้ยังมีประโยชน์ภายในชุดสังเคราะห์นี้อยู่ ใน 10 fixture ที่ถูกให้คะแนน goose3 ไม่ปล่อย token boilerplate ที่ติดป้ายกำกับไว้เลย ขณะที่ Readability ปล่อยออกมา 35 token บนหน้าเดียวกัน ถ้าระบบปลายทางนำผลลัพธ์ไปใช้งาน นั่นหมายถึงไม่มี token budget ที่สูญไปกับ boilerplate labels ใน 10 fixture นั้น แต่มันยังไม่พิสูจน์ว่าไม่มีความสูญเปล่าบนหน้าเว็บจริง และผลลัพธ์ว่างก็อาจสร้างต้นทุน fallback หรือ retry ในจุดอื่นของ pipeline ได้
ความเงียบ 2 ครั้ง และความหมายของมัน
goose3 ส่งอะไรกลับมาเลยใน 2 fixture พอดี หนึ่งอันพอเข้าใจได้ อีกอันคือข้อจำกัดจริง
เอกสารที่แทบว่างเปล่า หน้าเว็บที่มี article unit แค่ 1 หน่วย ยาว 32 ตัวอักษร goose3 ปฏิเสธที่จะดึง เช่นเดียวกับ jusText ใน fixture ชุดนี้ Readability ส่งผลลัพธ์ครบทั้ง 22 หน้า ดังนั้นผลของมันจึงไม่ได้สนับสนุนความเงียบของ goose3 ในกรณีนี้ การปฏิเสธเอกสารขนาดจิ๋วแบบนี้จะยอมรับได้หรือไม่ ขึ้นอยู่กับข้อตกลงขั้นต่ำของเนื้อหาที่ผู้เรียกใช้งานกำหนดไว้

บทความที่สร้างจาก <li> ล้วน ๆ มี article units 6 หน่วย และไม่มีหน่วยใดอยู่ในแท็ก <p> เลย goose3 ส่งสตริงว่างกลับมา
จุดนี้ทำให้ผมสงสัยอยู่เหมือนกัน เพราะการตั้งค่ามาตรฐานของ goose3 ระบุ parse_lists=True ไว้แล้ว จึงลองไล่ทดสอบ 3 คอนฟิกเทียบกับ control ที่ใช้งานได้ เพราะการรันแบบไม่เกิดผลเพียงครั้งเดียวไม่ใช่ข้อสรุปเกี่ยวกับไลบรารี
| Configuration | List-only page | <p> control |
|---|---|---|
| defaults | 0 chars | 937 chars |
strict=False | 0 chars | 937 chars |
parse_lists=True (explicit) | 0 chars | 937 chars |
ผลเป็นศูนย์ทั้งสามแบบ ขณะที่ control ให้ 937 ตัวอักษรทุกครั้ง ดังนั้น parse_lists=True จึงหมายถึงให้คง list ไว้ ภายในบทความที่ goose3 หาเจอแล้ว เท่านั้น ไม่ได้เปิดทางให้ตัวให้คะแนน candidate มอง list เป็น บทความได้ goose3 ต้องอาศัยบล็อกที่มีลักษณะเป็นย่อหน้าเพื่อหา body ให้เจอก่อน และถ้าหน้าใด body เป็น list ล้วนก็จะไม่มีโครงแบบนั้นให้จับ
ข้อสรุปที่ยืนยันได้แคบกว่านั้นคือ: body ที่มีรูปแบบเหมือน fixture สังเคราะห์นี้ — article units 6 หน่วย ทั้งหมดเป็น <li> ไม่มี candidate แบบ paragraph เลย — ส่งคืนสตริงว่าง บันทึกการเปลี่ยนแปลง, เอกสาร API, สูตรอาหาร, หน้า FAQ และบทความเปรียบเทียบ เป็นตัวอย่างความเสี่ยงที่สมเหตุสมผลสำหรับการทดสอบบนหน้าเว็บจริง เพราะมักมี list เยอะ แต่ fixture นี้เพียงตัวเดียวยังไม่พอจะสรุปว่าหมวดหน้าเว็บเหล่านั้นล้มเหลวเสมอไป
สตริงว่างตรวจจับได้ด้วยเครื่อง ก็ต่อเมื่อผู้เรียกตรวจสอบว่าผลลัพธ์ต้องไม่ว่าง เท่านั้น มันตั้งด่านง่ายกว่าข้อความที่ดูเหมือนจริงแต่ไม่มีเนื้อหาบทความอยู่เลย แต่ก็ยังเป็นความล้มเหลวแบบเงียบอยู่ดี ถ้าระบบมอนิเตอร์ตรวจแค่ exception เท่านั้น ฝั่ง production จึงควรมีการเช็ก minimum-output และมี fallback หรือบันทึกหน้าเว็บที่ล้มเหลวอย่างชัดเจน
ความจริงของการติดตั้ง
pip install goose3 ดึงมา 16 แพ็กเกจ และกินพื้นที่ 44.3 MiB ใช้เวลาประมาณ 6 ถึง 9 วินาที การวัด cold import ใน subprocess ใหม่พบว่าใช้เวลา 2.181 s
เอกสารอ้างอิงทางการ: goose3 บน PyPI.
| Library | Packages | site-packages | Cold import | Extraction p50 |
|---|---|---|---|---|
| resiliparse | 5 | 21.0 MiB | 0.015 s | 0.06 ms |
| jusText | 3 | 22.4 MiB | 0.777 s | 0.56 ms |
| goose3 | 16 | 44.3 MiB | 2.181 s | 1.85 ms |
| newspaper4k | 22 | 47.5 MiB | 2.812 s | 2.69 ms |
| trafilatura | 17 | 69.9 MiB | 1.584 s | 0.51 ms |
install-and-import.json. แต่ละไลบรารีอยู่ใน virtualenv ว่างของตัวเอง ดังนั้นไม่มี footprint ที่สืบทอดมาจากตัวอื่น.
น้ำหนักอยู่ระดับกลาง ๆ ความเร็วก็อยู่ระดับกลาง ๆ ติดตั้งและ import ได้เรียบร้อยบน Python 3.14.2 ซึ่งไม่ใช่เรื่องที่ทุกตัวในหมวดนี้ทำได้
3 ค่าเริ่มต้นที่ควรรู้ก่อนนำไปใช้งานจริง

ลองอ่านออบเจ็กต์ Configuration ที่มากับแพ็กเกจจริง ๆ แทนการอ่านเอกสารอย่างเดียว จะเจอการตั้งค่า 19 รายการ และ 3 รายการนี้มีโอกาสทำให้คนใช้งานสะดุ้ง
มันบอกตัวเองตรง ๆ browser_user_agent ตั้งต้นเป็น Goose/3.1.22 ถ้าปล่อยให้ goose3 ไปดึงหน้าเว็บเอง เซิร์ฟเวอร์ทุกแห่งที่คุณแตะจะเห็นชื่อไลบรารีและเวอร์ชันแบบชัดเจน ซึ่งตรงไปตรงมาดี แต่ก็เป็นลายนิ้วมือของเครื่องมือด้วย ตั้งค่าเองให้ชัดเจน หรือดึง HTML มาเองแล้วส่งผ่าน raw_html
มันชี้ไปที่ไบนารีของ MacPorts imagemagick_convert_path ตั้งต้นเป็น /opt/local/bin/convert และ imagemagick_identify_path เป็น /opt/local/bin/identify บนเครื่องผมไม่มีทั้งคู่ — /opt/local คือเส้นทางของ MacPorts ซึ่งคนส่วนใหญ่ไม่ได้ใช้; ส่วน Homebrew จะวางไบนารีไว้ที่ /opt/homebrew ค่าเริ่มต้นนี้จะไม่ก่อผลอะไรถ้าคุณไม่ได้เปิดการดึงรูป (enable_image_fetching ปิดไว้โดยค่าเริ่มต้น ซึ่งสมเหตุสมผล) แต่ถ้าเปิดแล้วหวังให้การดึงรูปหลักทำงาน นี่คือจุดที่มันอาจเงียบ ๆ แล้วไม่ทำงาน
มันสมมติว่าเป็นภาษาอังกฤษ target_language ตั้งไว้ที่ en และ use_meta_language=True ดังนั้นมันจะตามภาษาที่หน้าเว็บประกาศเองเมื่อมี และกลับไปใช้อังกฤษเมื่อไม่มี อันนี้โอเคสำหรับงานภาษาอังกฤษ แต่ถ้าเป็นภาษาอื่นก็ควรตั้งให้ชัด
ค่าอื่น ๆ ก็สมเหตุสมผล: parser_class คือ lxml, http_timeout 30 วินาที, strict เปิด, log_level เป็น ERROR, parse_headers และ keep_footnotes เปิด, images_min_bytes 4,000
หน่วยความจำ และ HTML ที่พังส่งผลอย่างไร
สองเรื่องที่รีวิวทุกชิ้นในชุดนี้ระบุว่าไม่ได้ทดสอบ ตอนนี้มีตัวเลขแล้ว
บริบทของ stress-test ที่กว้างกว่านี้ดูได้ใน การเปรียบเทียบหน่วยความจำและ HTML ที่เสียหายของเครื่องมือ 10 ตัว.
หน่วยความจำใช้งานสูงสุด วัดด้วย /usr/bin/time -l โดยใช้โปรเซสใหม่ทุกช่อง — floor ตอน import คือค่าใช้จ่ายตอนโหลดไลบรารีและปล่อยว่างไว้ ส่วนค่า peak รวมเอกสารเข้าไปด้วย
| Library | Runtime | Import floor | 226 KB peak | 10 MB peak |
|---|---|---|---|---|
| html2text | python3.14 | 18.7 | 19.9 | 71.2 |
| pyquery | python3.14 | 30.3 | 33.9 | 172.5 |
| resiliparse | python3.14 | 20.5 | 25.1 | 225.1 |
| markdownify | python3.14 | 23.9 | 28.9 | 278.5 |
| goose3 | python3.14 | 44.1 | 52.4 | 398.5 |
| cheerio | node22 | 66.8 | 76.5 | 398.5 |
| justext | python3.14 | 30.3 | 36.6 | 431.2 |
| newspaper4k | python3.14 | 52.6 | 61.8 | 668.5 |
| trafilatura | python3.14 | 52.5 | 64.8 | 927.1 |
| turndown | node22 | 47.8 | 68.4 | 2947.1 |
memory-results.json. ค่า baseline ของ Python และ Node เทียบกันตรง ๆ ไม่ได้ เพราะ interpreter อยู่ข้างในทั้งคู่.
goose3 มี floor ที่ 44.1 MiB และ peak ที่ 398.5 MiB บนเอกสารขนาด 10 MB ค่า import floor ของมันสูงเป็นอันดับ 3 ในบรรดาไลบรารี Python ที่แสดงไว้ ซึ่งควรรู้ไว้ถ้าระบบของคุณไวต่อ cold start
HTML ที่เสียหาย เอกสาร 12 ชิ้นที่พังอย่างละแบบ — แท็กไม่ปิด, inline elements ซ้อนผิด, แอตทริบิวต์ไม่ใส่เครื่องหมายคำพูดทั้งที่มีช่องว่าง, closing tag โผล่เกิน, ไม่มี <html> เลย, แอตทริบิวต์ซ้ำ, เอกสารถูกตัดกลางแท็ก, entities ผิด, <script> ไม่ปิด, ประกาศ charset หลอก, คอมเมนต์ที่มี markup อยู่ข้างใน, และการซ้อนลึกถึง 600 ชั้น — บวกกับ control ที่ถูกต้องตามโครงสร้าง 2 ชุดที่ขนาดเท่ากัน เพราะคำว่า “มันไม่ส่งอะไรกลับมา” จะบอกเรื่อง malformed ได้ก็ต่อเมื่อไลบรารีไม่ได้เงียบกับเอกสารสะอาดขนาดเดียวกันด้วย
goose3 ไม่ throw exception ใน 0 จาก 14 และส่งค่าว่างใน 10 ชิ้น กู้คืน sentinel ได้ 2/33 ตัวจาก fixture ที่เสียหาย (malformed-results.json). มี 1 fixture ที่ไม่นับในตัวเลขนี้: ตาม HTML5 ทุกอย่างหลัง <script> ที่ไม่ปิดถือว่าเป็น script content อยู่แล้ว ดังนั้นการหายไปตรงนั้นจึงถูกต้อง และการกู้กลับมาได้ต่างหากที่เป็นความเบี่ยงเบน
ข้อดีและข้อเสีย
ข้อดี ไม่มี boilerplate tokens ที่ติดป้ายกำกับเลยใน 10 fixture ด้าน content-fidelity ที่มันส่งผลลัพธ์ออกมา มีฟิลด์บทความให้ใช้ราว 28 รายการ แม้ความแม่นยำของแต่ละฟิลด์จะถูกสำรวจไว้แต่ไม่ได้ให้คะแนน การดึงรูปตั้งต้นสมเหตุสมผล (ปิดไว้) ติดตั้งสะอาดบน Python 3.14 ยังมีการดูแลต่อเนื่อง และใช้สัญญาอนุญาต Apache-2.0 ผลลัพธ์ว่างตรวจดักได้ง่ายถ้าผู้เรียกเช็กอย่างชัดเจน
ข้อเสีย recall ของบทความต่ำที่สุดในชุดที่ 0.8243 โดยเกิดจากการไม่ส่งอะไรกลับมาเลย ไม่ใช่เพราะส่งของผิด หน้าเว็บที่บทความเป็น list จะได้สตริงว่างไม่ว่าจะตั้งค่าอย่างไร หน่วยความจำ 44.3 MiB และ cold import 2.2 วินาที หนักกว่า resiliparse ที่ 21.0 MiB และ 15 ms ต้องเรียก close() ด้วย และค่าเริ่มต้นสองตัวชี้ไปยังสิ่งที่ผิดบนเครื่องส่วนใหญ่
ใครควรใช้ และใครไม่ควรใช้
ควรใช้ goose3 เป็นตัวเลือกหนึ่ง เมื่อข้อความที่ดึงออกไปจะเข้าสู่โมเดลหรือฐานข้อมูลที่ boilerplate ที่ติดป้ายกำกับไว้มีต้นทุนสูง และหน้าเว็บส่วนใหญ่เป็นบทความแบบย่อหน้า บนชุด fixture นี้มันไม่ปล่อย token boilerplate ที่ติดป้ายกำกับเลยตอนที่ตอบกลับมา เมตาดาตาใช้งานได้ แต่ในบทความนี้ยังไม่ได้ตรวจสอบความถูกต้อง จึงยังต้องมี fixture truth แยกต่างหากก่อนจะถือเป็นจุดขาย
ไม่ควรใช้ ถ้าคอร์ปัสของคุณเป็น list-heavy — คุณจะได้สตริงว่างและไม่มีคำอธิบาย ไม่ควรใช้ถ้าความเร็วตอน cold start สำคัญ เพราะ resiliparse import ได้เร็วกว่า 145 เท่า และไม่ควรใช้ถ้าคุณต้องการคำตอบทุกหน้า เพราะที่นี่ “ไม่มีคำตอบ” คือผลลัพธ์จริง ๆ: 2 จาก 22 fixture และเงียบแบบเงียบจริง ๆ คือเป็น empty string ไม่ใช่ exception
คู่ที่ควรลองทดสอบ: ใช้ goose3 เป็นตัวหลัก แล้วมี fallback เมื่อ cleaned_text ว่างหรือสั้นกว่ากฎเนื้อหาขั้นต่ำของคุณ Readability กู้คืน article unit ได้ครบทุกตัวในชุด 22 fixture นี้ รวมถึงสองกรณีที่ goose3 ส่งค่าว่าง ผลสังเคราะห์แบบนี้สนับสนุนรูปแบบสถาปัตยกรรม ไม่ได้สัญญาว่า fallback จะไม่พลาดบนหน้าเว็บจริงเลย
บทบาทของ Managed API
การทดสอบนี้วัดเส้นทาง raw_html ของ goose3: HTML ถูกดึงมาก่อนที่ goose3 จะเห็นมัน goose3 เองก็มีเส้นทางดึงผ่านเครือข่ายตามที่การตั้งค่า User-Agent บอกไว้ แต่เส้นทางนั้นไม่ได้ทดสอบในที่นี้ การเรนเดอร์ JavaScript และพฤติกรรมต้านบอทก็ไม่ได้ทดสอบเช่นกัน
ถ้าอยากดูผลของ fixture เดียวกันทั้ง 6 extractor ดูได้ที่ การเปรียบเทียบการสกัดบทความของไลบรารีทั้งหก.
บริการแบบ managed สำหรับดึง/เรนเดอร์/สกัด รวมถึง Thunderbit ของเราเอง อยู่คนละขอบเขตความรับผิดชอบ Thunderbit ไม่ได้ถูกนำมาวัดในชุดทดสอบนี้ ความต่างที่สำคัญคือการสกัดบทความจาก HTML ที่ส่งมาให้ กับบริการโฮสต์ที่เป็นผู้ดึงและประมวลผล URL บทความนี้จึงไม่มีการเปรียบเทียบแบบ metric ต่อ metric ระหว่างกัน
ถ้าจะเปรียบเทียบอย่างเป็นธรรม ชุดฟิลด์ของ goose3 ถูกออกแบบมาเป็นบทความโดยตรง ซึ่งเหมาะมากเมื่อหน้าเว็บเป็นบทความ และไม่เหมาะเมื่อเป็นรายการสินค้า ถ้าคุณมี HTML อยู่แล้วและหน้าเว็บของคุณเป็นบทความ goose3 ก็ฟรีและสะอาดมาก
ถ้าอยากดูภาพรวมฝั่งโฮสต์ อ่าน สรุป API สำหรับ web scraping; ถ้าอยากดูตัวเลือก open-source ฝั่ง self-hosted ดู pillar open-source scraper. ถ้าข้อความจะถูกส่งเข้าโมเดล การแปลง HTML เป็น Markdown ใน Python จะอธิบายว่าความเที่ยงตรงหายไปตรงไหนบ้าง
ลองใช้ Thunderbit เพื่อดึงข้อมูลเว็บ
ควรใช้ goose3 ไหม?
ควร ถ้าย่อหน้าของบทความคือรูปแบบงานหลักของคุณ และฝั่งเรียกใช้งานมองว่าผลลัพธ์ว่างคือการดึงล้มเหลว ไม่ใช่ความสำเร็จ
ในชุด fixture นี้ goose3 ไม่ปล่อย boilerplate tokens ที่ติดป้ายกำกับเลยตอนที่ตอบกลับมา และส่งสตริงว่าง 2 ครั้ง หนึ่งครั้งเป็นหน้าเกือบว่าง อีกครั้งเป็น body ที่เป็น list ล้วน ๆ นี่คือการแลก precision กับ coverage ไม่ใช่หลักฐานว่ามันมีนิสัยแบบไหนในทั้งผลิตภัณฑ์
ถ้า recall สำคัญกว่า ให้ทดสอบ fallback พร้อม minimum-output guard ที่ชัดเจน Readability กู้คืน article unit ได้ครบทุกตัวใน 22 fixture นี้; newspaper4k ไม่มี boilerplate-unit leak เลย และมี recall 0.9865 พร้อมส่งผลลัพธ์ครบ 22 หน้า ตัวเลขเหล่านี้สะท้อนชุดสังเคราะห์นี้ภายใต้ค่าเริ่มต้น ไม่ใช่งาน production ที่ยังไม่รู้รูปแบบ
goose3 จะคุ้มค่าเมื่อราคาของคำที่ผิดสูงกว่าราคาของหน้าที่หายไป
ลองใช้ Thunderbit เพื่อดึงข้อมูลเว็บ Get Started Free
คำถามที่พบบ่อย
precision ที่สมบูรณ์แบบของ goose3 เป็นของจริง หรือเป็นเพราะมันเลือกไม่ตอบ? ทั้งสองอย่าง และแยกจากกันได้ มันถูกให้คะแนนจาก 10 ใน 11 fixture ที่มี boilerplate ดังนั้นค่าเฉลี่ยจึงขาดไป 1 fixture — ส่วนนั้นเป็นผลจากการไม่ตอบ แต่ใน 10 fixture ที่เหลือมันไม่ปล่อย contaminating tokens เลย ทั้งที่ boilerplate ถูกออกแบบมาให้ขัดขวางโดยตรง ขณะที่ Readability ปล่อยออกมา 35 token precision จึงจริงสำหรับหน้าที่มันตอบ ส่วน recall คือคอลัมน์ที่สะท้อนการไม่ตอบ
ทำไม goose3 ถึงส่งค่าว่างเมื่อบทความเป็น list?
ตัวให้คะแนน candidate ของมันต้องใช้บล็อกที่มีรูปทรงเหมือนย่อหน้าเพื่อหา body ของบทความ และหน้าที่สร้างจาก <li> ก็ไม่มีบล็อกแบบนั้น parse_lists=True ที่เป็นค่าเริ่มต้นไม่ได้เปลี่ยนเรื่องนี้ — ผมลองตั้งแบบ explicit แล้ว รวมถึง strict=False ด้วย ผลคือได้ศูนย์ตัวอักษรทั้งสามคอนฟิก ขณะที่ control แบบ <p> ให้ 937 ทุกครั้ง parse_lists มีไว้กำหนดว่าจะเก็บ list ไว้ภายในบทความที่หาเจอแล้วหรือไม่
ต้องเรียก close() ไหม?
ควรปิดอย่างชัดเจนด้วย try/finally ตามตัวอย่างข้างบน บทความรีวิวนี้ไม่ได้วัดว่ามีอะไรสะสมเมื่อไม่ปิด จึงไม่ได้อ้างว่าเกิด loop leak แบบวัดได้ แต่ยืนยันได้ว่า Goose มี lifecycle ที่ผู้เรียกต้องจัดการ
goose3 ส่ง User-Agent อะไร?
ค่าเริ่มต้นคือ Goose/3.1.22 — คือชื่อไลบรารีกับเวอร์ชันแบบตรงตัว ซึ่งใช้เฉพาะตอนที่ปล่อยให้มันไปดึงเอง ถ้าคุณส่ง raw_html เข้าไป ก็จะข้ามส่วนนี้ไปเลย ถ้าให้มันดึงเอง ควรตั้ง User-Agent เองให้ชัด เพราะค่าเริ่มต้นจะบอกทุกเซิร์ฟเวอร์ที่คุณแตะว่ามีอะไรเป็นตัวเรียก
รีวิวนี้ไม่ได้ทดสอบอะไรบ้าง?
ไม่ได้ทดสอบหน้าเว็บจริงเลย — ทั้งหมดเป็น fixture ที่ควบคุมไว้ ไม่ได้ทดสอบการสกัดหลายภาษา แม้ target_language จะเป็นการตั้งค่าหลัก เมตาดาตา เช่น title, authors, date, top image ถูกสำรวจไว้แต่ไม่ได้ให้คะแนนความถูกต้อง ไม่ได้ทดสอบการดึงรูป ซึ่งปิดไว้โดยค่าเริ่มต้นและชี้ path ของ ImageMagick ไปยัง package manager ที่เครื่องส่วนใหญ่ไม่มี รวมถึงไม่ได้ทดสอบพฤติกรรมหน่วยความจำภายใต้ concurrent หรือ sustained load และ throughput ภายใต้โหลด; ตารางหน่วยความจำวัดจากโปรเซสใหม่หนึ่งตัวที่ประมวลผลเอกสารหนึ่งชิ้น


