คุณแยกวิเคราะห์และประมวลผล HTML / XML ใน PHP อย่างไร?
เราจะแยกวิเคราะห์ HTML / XML และดึงข้อมูลจากมันได้อย่างไร?
คำตอบ
ส่วนขยาย XML ดั้งเดิม
ฉันชอบใช้ส่วนขยาย XML ดั้งเดิมเนื่องจากมาพร้อมกับ PHP โดยปกติจะเร็วกว่า libs ของบุคคลที่สามทั้งหมดและให้การควบคุมทั้งหมดที่ฉันต้องการผ่านมาร์กอัป
DOM
ส่วนขยาย DOM ช่วยให้คุณสามารถดำเนินการกับเอกสาร XML ผ่าน DOM API ด้วย PHP 5 เป็นการใช้งาน Document Object Model Core ระดับ 3 ของ W3C ซึ่งเป็นอินเทอร์เฟซที่เป็นกลางของแพลตฟอร์มและภาษาที่ช่วยให้โปรแกรมและสคริปต์สามารถเข้าถึงและอัปเดตได้แบบไดนามิก เนื้อหาโครงสร้างและรูปแบบของเอกสาร
DOM สามารถแยกวิเคราะห์และแก้ไข HTML โลกแห่งความจริง (เสีย) และสามารถทำแบบสอบถาม XPathได้ มันขึ้นอยู่กับlibxml
ต้องใช้เวลาพอสมควรในการทำงานร่วมกับ DOM แต่เวลานั้นก็คุ้มค่ากับ IMO เนื่องจาก DOM เป็นอินเทอร์เฟซที่ไม่เชื่อเรื่องพระเจ้าคุณจะพบการใช้งานในหลายภาษาดังนั้นหากคุณต้องการเปลี่ยนภาษาการเขียนโปรแกรมโอกาสที่คุณจะรู้วิธีใช้ DOM API ของภาษานั้นแล้ว
ตัวอย่างการใช้งานพื้นฐานสามารถพบได้ในการจับแอตทริบิวต์ href ขององค์ประกอบ Aและภาพรวมแนวคิดทั่วไปสามารถพบได้ที่DOMDocument ใน php
วิธีใช้ส่วนขยาย DOM ได้รับการกล่าวถึงอย่างกว้างขวางใน StackOverflowดังนั้นหากคุณเลือกใช้คุณสามารถมั่นใจได้ว่าปัญหาส่วนใหญ่ที่คุณพบสามารถแก้ไขได้โดยการค้นหา / เรียกดู Stack Overflow
XMLReader
ส่วนขยาย XMLReader เป็นตัวแยกวิเคราะห์ดึง XML เครื่องอ่านทำหน้าที่เป็นเคอร์เซอร์ไปข้างหน้าในสตรีมเอกสารและหยุดที่แต่ละโหนดระหว่างทาง
XMLReader เช่น DOM ขึ้นอยู่กับ libxml ฉันไม่ทราบวิธีเรียกใช้โมดูลตัวแยกวิเคราะห์ HTML ดังนั้นโอกาสที่จะใช้ XMLReader สำหรับการแยกวิเคราะห์ HTML ที่ใช้งานไม่ได้อาจมีประสิทธิภาพน้อยกว่าการใช้ DOM ซึ่งคุณสามารถบอกให้ใช้โมดูลตัวแยกวิเคราะห์ HTML ของ libxml ได้อย่างชัดเจน
ตัวอย่างการใช้งานพื้นฐานสามารถพบได้ในการรับค่าทั้งหมดจากแท็ก h1 โดยใช้ php
ตัวแยกวิเคราะห์ XML
ส่วนขยายนี้ช่วยให้คุณสร้างตัวแยกวิเคราะห์ XML จากนั้นกำหนดตัวจัดการสำหรับเหตุการณ์ XML ต่างๆ ตัวแยกวิเคราะห์ XML แต่ละตัวยังมีพารามิเตอร์บางอย่างที่คุณสามารถปรับเปลี่ยนได้
ไลบรารี XML Parser ยังขึ้นอยู่กับ libxml และใช้ตัวแยกวิเคราะห์การพุช XML สไตล์SAX อาจเป็นทางเลือกที่ดีกว่าสำหรับการจัดการหน่วยความจำมากกว่า DOM หรือ SimpleXML แต่จะใช้งานได้ยากกว่าตัวแยกวิเคราะห์แบบดึงที่ใช้โดย XMLReader
SimpleXml
ส่วนขยาย SimpleXML มีชุดเครื่องมือที่เรียบง่ายและใช้งานได้ง่ายในการแปลง XML เป็นอ็อบเจ็กต์ที่สามารถประมวลผลด้วยตัวเลือกคุณสมบัติปกติและตัวทำซ้ำอาร์เรย์
SimpleXML เป็นตัวเลือกเมื่อคุณทราบว่า HTML เป็น XHTML ที่ถูกต้อง หากคุณต้องการแยกวิเคราะห์ HTML ที่ใช้งานไม่ได้อย่าพิจารณา SimpleXml ด้วยซ้ำเพราะจะทำให้หายใจไม่ออก
ตัวอย่างการใช้งานพื้นฐานสามารถพบได้ที่โปรแกรมที่ง่ายต่อ CRUD โหนดและโหนดค่าของไฟล์ XMLและมีจำนวนมากตัวอย่างเพิ่มเติมในคู่มือการใช้งานของ PHP
ไลบรารีของบุคคลที่สาม (อิงจาก libxml)
หากคุณต้องการใช้ lib ของบุคคลที่สามฉันขอแนะนำให้ใช้ lib ที่ใช้DOM / libxmlด้านล่างแทนการแยกวิเคราะห์สตริง
FluentDom - Repo
FluentDOM มีอินเทอร์เฟซ XML ที่คล่องแคล่วเหมือน jQuery สำหรับ DOMDocument ใน PHP ตัวเลือกถูกเขียนด้วย XPath หรือ CSS (โดยใช้ตัวแปลง CSS เป็น XPath) เวอร์ชันปัจจุบันขยาย DOM ที่ใช้อินเทอร์เฟซมาตรฐานและเพิ่มคุณสมบัติจาก DOM Living Standard FluentDOM สามารถโหลดรูปแบบเช่น JSON, CSV, JsonML, RabbitFish และอื่น ๆ สามารถติดตั้งผ่าน Composer
HtmlPageDom
Wa72 \ HtmlPageDom` เป็นไลบรารี PHP สำหรับการจัดการเอกสาร HTML อย่างง่ายดายโดยใช้มันต้องใช้DomCrawler จากคอมโพเนนต์ Symfony2สำหรับการสำรวจ DOM ทรีและขยายโดยการเพิ่มเมธอดในการจัดการโครงสร้าง DOM ของเอกสาร HTML
phpQuery (ไม่ได้อัปเดตเป็นเวลาหลายปี)
phpQuery เป็นตัวเลือก CSS3 ที่ขับเคลื่อนด้วย Document Object Model (DOM) ฝั่งเซิร์ฟเวอร์โดยใช้ jQuery JavaScript Library ที่เขียนด้วย PHP5 และมี Command Line Interface (CLI) เพิ่มเติม
ดูเพิ่มเติมที่: https://github.com/electrolinux/phpquery
Zend_Dom
Zend_Dom มีเครื่องมือสำหรับการทำงานกับเอกสารและโครงสร้าง DOM ปัจจุบันเรานำเสนอ Zend_Dom_Query ซึ่งมีอินเทอร์เฟซแบบรวมสำหรับการสืบค้นเอกสาร DOM โดยใช้ทั้งตัวเลือก XPath และ CSS
QueryPath
QueryPath เป็นไลบรารี PHP สำหรับจัดการ XML และ HTML ไม่เพียง แต่ออกแบบมาเพื่อใช้งานกับไฟล์ในเครื่องเท่านั้น แต่ยังรวมถึงบริการเว็บและทรัพยากรฐานข้อมูลด้วย มันใช้อินเทอร์เฟซ jQuery ส่วนใหญ่ (รวมถึงตัวเลือกสไตล์ CSS) แต่ได้รับการปรับแต่งอย่างมากสำหรับการใช้งานฝั่งเซิร์ฟเวอร์ สามารถติดตั้งผ่าน Composer
fDOMDocument
fDOMDocument ขยาย DOM มาตรฐานเพื่อใช้ข้อยกเว้นในทุกโอกาสที่เกิดข้อผิดพลาดแทนคำเตือนหรือประกาศของ PHP นอกจากนี้ยังเพิ่มวิธีการและทางลัดแบบกำหนดเองต่างๆเพื่อความสะดวกและเพื่อลดความซับซ้อนในการใช้งาน DOM
กระบี่ / xml
saber / xml เป็นไลบรารีที่รวมและขยายคลาส XMLReader และ XMLWriter เพื่อสร้างระบบการแมป "xml to object / array" และรูปแบบการออกแบบอย่างง่าย การเขียนและอ่าน XML เป็นแบบ single-pass ดังนั้นจึงรวดเร็วและต้องการหน่วยความจำต่ำสำหรับไฟล์ xml ขนาดใหญ่
FluidXML
FluidXML เป็นไลบรารี PHP สำหรับจัดการ XML ด้วย API ที่กระชับและคล่องแคล่ว ใช้ประโยชน์จาก XPath และรูปแบบการเขียนโปรแกรมที่คล่องแคล่วเพื่อให้สนุกและมีประสิทธิภาพ
บุคคลที่สาม (ไม่ใช้ libxml)
ประโยชน์ของการสร้าง DOM / libxml คือคุณจะได้รับประสิทธิภาพที่ดีนอกกรอบเนื่องจากคุณใช้ส่วนขยายดั้งเดิม อย่างไรก็ตาม libs ของบุคคลที่สามทั้งหมดไม่ได้ลงเส้นทางนี้ บางส่วนของรายการด้านล่าง
PHP Parser HTML DOM แบบง่าย
- ตัวแยกวิเคราะห์ HTML DOM ที่เขียนด้วย PHP5 + ช่วยให้คุณจัดการ HTML ได้อย่างง่ายดาย!
- ต้องการ PHP 5+
- รองรับ HTML ที่ไม่ถูกต้อง
- ค้นหาแท็กบนหน้า HTML ด้วยตัวเลือกเช่นเดียวกับ jQuery
- แยกเนื้อหาจาก HTML ในบรรทัดเดียว
โดยทั่วไปฉันไม่แนะนำตัวแยกวิเคราะห์นี้ โค้ดเบสนั้นน่ากลัวและตัวแยกวิเคราะห์ค่อนข้างช้าและความจำหิว ตัวเลือก jQuery บางตัวเท่านั้นที่เป็นไปได้(เช่นตัวเลือกลูก ) ไลบรารีที่ใช้ libxml ใด ๆ ควรมีประสิทธิภาพดีกว่านี้ได้อย่างง่ายดาย
PHP Html Parser
PHPHtmlParser เป็นโปรแกรมแยกวิเคราะห์ html ที่เรียบง่ายยืดหยุ่นซึ่งช่วยให้คุณสามารถเลือกแท็กโดยใช้ตัวเลือก css เช่น jQuery เป้าหมายคือเพื่อช่วยในการพัฒนาเครื่องมือที่ต้องการวิธีที่ง่ายและรวดเร็วในการคัดลอก html ไม่ว่าจะถูกต้องหรือไม่ก็ตาม! โครงการนี้ได้รับการสนับสนุนโดย sunra / php-simple-html-dom-parser แต่ดูเหมือนว่าการสนับสนุนจะหยุดลงดังนั้นโครงการนี้จึงเป็นการดัดแปลงงานก่อนหน้าของเขา
อีกครั้งฉันไม่อยากแนะนำตัวแยกวิเคราะห์นี้ ค่อนข้างช้าเนื่องจากมีการใช้งาน CPU สูง นอกจากนี้ยังไม่มีฟังก์ชันในการล้างหน่วยความจำของวัตถุ DOM ที่สร้างขึ้น ปัญหาเหล่านี้ขยายขนาดโดยเฉพาะกับลูปที่ซ้อนกัน เอกสารประกอบเองไม่ถูกต้องและสะกดผิดโดยไม่มีการตอบสนองในการแก้ไขตั้งแต่วันที่ 14 เม.ย. 59
กานอน
- โทเค็นไนเซอร์สากลและตัวแยกวิเคราะห์ HTML / XML / RSS DOM
- ความสามารถในการจัดการองค์ประกอบและคุณลักษณะ
- รองรับ HTML และ UTF8 ที่ไม่ถูกต้อง
- สามารถดำเนินการค้นหาขั้นสูงคล้าย CSS3 บนองค์ประกอบ (เช่น jQuery - รองรับเนมสเปซ)
- เครื่องมือตกแต่ง HTML (เช่น HTML Tidy)
- ลดขนาด CSS และ Javascript
- จัดเรียงแอตทริบิวต์เปลี่ยนตัวพิมพ์เล็กและใหญ่การเยื้องที่ถูกต้อง ฯลฯ
- ขยายได้
- การแยกวิเคราะห์เอกสารโดยใช้การเรียกกลับตามอักขระ / โทเค็นปัจจุบัน
- การดำเนินการแยกออกในฟังก์ชันที่เล็กลงเพื่อให้ง่ายต่อการลบล้าง
- ง่ายและรวดเร็ว
ไม่เคยใช้. ไม่สามารถบอกได้ว่ามันดีหรือไม่
HTML 5
คุณสามารถใช้ข้างต้นในการแยกวิเคราะห์ HTML5 แต่อาจมีความแปลกใหม่เนื่องจาก HTML5 อนุญาตให้มาร์กอัป ดังนั้นสำหรับ HTML5 คุณควรพิจารณาใช้ตัวแยกวิเคราะห์เฉพาะเช่น
html5lib
การใช้งาน Python และ PHP ของตัวแยกวิเคราะห์ HTML ตามข้อกำหนด WHATWG HTML5 เพื่อความเข้ากันได้สูงสุดกับเว็บเบราว์เซอร์เดสก์ท็อปหลัก ๆ
เราอาจเห็นตัวแยกวิเคราะห์เฉพาะเพิ่มเติมเมื่อสรุป HTML5 แล้ว นอกจากนี้ยังมีบล็อกโพสต์โดย W3 ที่มีชื่อว่าHow-To สำหรับการแยกวิเคราะห์ html 5ที่ควรค่าแก่การตรวจสอบ
WebServices
หากคุณไม่อยากเขียนโปรแกรม PHP คุณสามารถใช้บริการเว็บได้เช่นกัน โดยทั่วไปฉันพบยูทิลิตี้เหล่านี้น้อยมาก แต่นั่นเป็นเพียงตัวฉันและกรณีการใช้งานของฉัน
ScraperWiki
อินเทอร์เฟซภายนอกของ ScraperWiki ช่วยให้คุณสามารถดึงข้อมูลในรูปแบบที่คุณต้องการเพื่อใช้บนเว็บหรือในแอปพลิเคชันของคุณเอง คุณยังสามารถดึงข้อมูลเกี่ยวกับสถานะของมีดโกนได้
นิพจน์ทั่วไป
ที่ผ่านมาและน้อยแนะนำให้คุณสามารถดึงข้อมูลจาก HTML ที่มีการแสดงออกปกติ โดยทั่วไปไม่แนะนำให้ใช้นิพจน์ทั่วไปบน HTML
ตัวอย่างข้อมูลส่วนใหญ่ที่คุณจะพบบนเว็บเพื่อจับคู่มาร์กอัปนั้นเปราะบาง ในกรณีส่วนใหญ่พวกเขาใช้งานได้เฉพาะกับ HTML บางส่วนเท่านั้น การเปลี่ยนแปลงมาร์กอัปเล็ก ๆ เช่นการเพิ่มช่องว่างที่ใดที่หนึ่งหรือการเพิ่มหรือการเปลี่ยนแอตทริบิวต์ในแท็กสามารถทำให้ RegEx ล้มเหลวเมื่อเขียนไม่ถูกต้อง คุณควรรู้ว่าคุณกำลังทำอะไรก่อนที่จะใช้ RegEx บน HTML
โปรแกรมแยกวิเคราะห์ HTML รู้กฎไวยากรณ์ของ HTML อยู่แล้ว ต้องมีการสอนนิพจน์ทั่วไปสำหรับ RegEx ใหม่แต่ละรายการที่คุณเขียน RegEx ใช้ได้ดีในบางกรณี แต่ขึ้นอยู่กับกรณีการใช้งานของคุณจริงๆ
คุณสามารถเขียนตัวแยกวิเคราะห์ที่เชื่อถือได้มากขึ้นแต่การเขียนตัวแยกวิเคราะห์แบบกำหนดเองที่สมบูรณ์และเชื่อถือได้ด้วยนิพจน์ทั่วไปจะเสียเวลาเมื่อมีไลบรารีดังกล่าวอยู่แล้วและทำงานได้ดีกว่ามากในเรื่องนี้
นอกจากนี้โปรดดูการแยกวิเคราะห์ Html The Cthulhu Way
หนังสือ
หากคุณต้องการใช้จ่ายเงินลองดูที่
- คู่มือสถาปนิก PHP สำหรับการทำเว็บไซต์ด้วย PHP
ฉันไม่มีส่วนเกี่ยวข้องกับ PHP Architect หรือผู้เขียน
ลองใช้ตัวแยกวิเคราะห์ HTML DOM แบบง่าย
- โปรแกรมแยกวิเคราะห์ HTML DOM ที่เขียนด้วย PHP 5+ ที่ช่วยให้คุณจัดการ HTML ได้อย่างง่ายดาย!
- ต้องการ PHP 5+
- รองรับ HTML ที่ไม่ถูกต้อง
- ค้นหาแท็กบนหน้า HTML ด้วยตัวเลือกเช่นเดียวกับ jQuery
- แยกเนื้อหาจาก HTML ในบรรทัดเดียว
- ดาวน์โหลด
ตัวอย่าง:
วิธีรับองค์ประกอบ HTML:
// Create DOM from URL or file
$html = file_get_html('http://www.example.com/'); // Find all images foreach($html->find('img') as $element) echo $element->src . '<br>';
// Find all links
foreach($html->find('a') as $element)
echo $element->href . '<br>';
วิธีแก้ไของค์ประกอบ HTML:
// Create DOM from string
$html = str_get_html('<div id="hello">Hello</div><div id="world">World</div>');
$html->find('div', 1)->class = 'bar'; $html->find('div[id=hello]', 0)->innertext = 'foo';
echo $html;
แยกเนื้อหาจาก HTML:
// Dump contents (without tags) from HTML
echo file_get_html('http://www.google.com/')->plaintext;
ขูด Slashdot:
// Create DOM from URL
$html = file_get_html('http://slashdot.org/');
// Find all article blocks
foreach($html->find('div.article') as $article) {
$item['title'] = $article->find('div.title', 0)->plaintext;
$item['intro'] = $article->find('div.intro', 0)->plaintext;
$item['details'] = $article->find('div.details', 0)->plaintext;
$articles[] = $item;
}
print_r($articles);
เพียงใช้DOMDocument-> loadHTML ()และดำเนินการให้เสร็จสิ้น อัลกอริทึมการแยกวิเคราะห์ HTML ของ libxml นั้นค่อนข้างดีและรวดเร็วและตรงกันข้ามกับความเชื่อที่ได้รับความนิยมไม่ได้สำลัก HTML ที่มีรูปแบบไม่ถูกต้อง
เหตุใดคุณจึงไม่ควรใช้และเมื่อใดจึงควรใช้นิพจน์ทั่วไป
ปิดแรกบริบททั่วไป: regexps ไม่ได้สำหรับ" แยก " HTML อย่างไรก็ตาม Regexes สามารถ" ดึงข้อมูล"ได้ การแยกคือสิ่งที่พวกเขาสร้างขึ้น ข้อเสียเปรียบที่สำคัญของการแยก regex HTML เหนือชุดเครื่องมือ SGML ที่เหมาะสมหรือตัวแยกวิเคราะห์ XML พื้นฐานคือความพยายามในการใช้วากยสัมพันธ์และความน่าเชื่อถือที่แตกต่างกัน
พิจารณาว่าการสร้าง regex การแยก HTML ที่เชื่อถือได้:
<a\s+class="?playbutton\d?[^>]+id="(\d+)".+? <a\s+class="[\w\s]*title
[\w\s]*"[^>]+href="(http://[^">]+)"[^>]*>([^<>]+)</a>.+?
เป็นวิธีที่อ่านได้น้อยกว่า phpQuery ธรรมดาหรือเทียบเท่า QueryPath:
$div->find(".stationcool a")->attr("title");
อย่างไรก็ตามมีกรณีการใช้งานเฉพาะที่สามารถช่วยได้
- ส่วนหน้าการส่งผ่าน DOM จำนวนมากไม่เปิดเผยความคิดเห็น HTML
<!--
ซึ่งบางครั้งก็เป็นจุดยึดที่มีประโยชน์มากกว่าสำหรับการแยก โดยเฉพาะรูปแบบหลอก HTML<$var>
หรือ SGML ตกค้างนั้นง่ายต่อการเชื่องด้วย regexps - บ่อยครั้งนิพจน์ทั่วไปสามารถบันทึกหลังการประมวลผลได้ อย่างไรก็ตามเอนทิตี HTML มักต้องการการดูแลด้วยตนเอง
- และประการสุดท้ายสำหรับงานที่เรียบง่ายอย่างยิ่งเช่นการแยก <img src = urls พวกเขาเป็นเครื่องมือที่น่าจะเป็นไปได้ ข้อได้เปรียบด้านความเร็วเหนือตัวแยกวิเคราะห์ SGML / XML ส่วนใหญ่มาเพื่อเล่นสำหรับขั้นตอนการแยกขั้นพื้นฐานเหล่านี้
บางครั้งแนะนำให้ดึงข้อมูลโค้ด HTML ไว้ล่วงหน้าโดยใช้นิพจน์ทั่วไป/<!--CONTENT-->(.+?)<!--END-->/
และประมวลผลส่วนที่เหลือโดยใช้ส่วนหน้าของตัวแยกวิเคราะห์ HTML ที่ง่ายกว่า
หมายเหตุ:จริงๆแล้วฉันมีแอพนี้ซึ่งฉันใช้การแยกวิเคราะห์ XML และนิพจน์ทั่วไปอีกทางหนึ่ง เมื่อสัปดาห์ที่แล้วการแยกวิเคราะห์ PyQuery หยุดทำงานและ regex ยังคงใช้งานได้ ใช่แปลกและฉันไม่สามารถอธิบายได้ด้วยตัวเอง แต่มันก็เกิดขึ้น
ดังนั้นโปรดอย่าโหวตข้อพิจารณาในโลกแห่งความเป็นจริงเพียงเพราะมันไม่ตรงกับ regex = evil meme แต่อย่าโหวตมากเกินไป เป็นเพียงแนวทางสำหรับหัวข้อนี้
phpQueryและQueryPathมีความคล้ายคลึงกันมากในการจำลอง jQuery API ที่คล่องแคล่ว นั่นเป็นเหตุผลว่าทำไมจึงเป็นสองวิธีที่ง่ายที่สุดในการแยกวิเคราะห์ HTML ใน PHP อย่างถูกต้อง
ตัวอย่างสำหรับ QueryPath
โดยพื้นฐานแล้วคุณต้องสร้างแผนผัง DOM ที่สามารถสอบถามได้จากสตริง HTML ก่อน:
$qp = qp("<html><body><h1>title</h1>..."); // or give filename or URL
อ็อบเจ็กต์ผลลัพธ์มีการแสดงโครงสร้างแบบสมบูรณ์ของเอกสาร HTML สามารถข้ามผ่านได้โดยใช้วิธี DOM แต่วิธีการทั่วไปคือการใช้ตัวเลือก CSS เช่นใน jQuery:
$qp->find("div.classname")->children()->...;
foreach ($qp->find("p img") as $img) {
print qp($img)->attr("src");
}
ส่วนใหญ่คุณต้องการใช้ง่าย#id
และ.class
หรือแท็กเตอร์สำหรับDIV
->find()
แต่คุณยังสามารถใช้คำสั่งXPathซึ่งบางครั้งก็เร็วกว่า วิธีการทั่วไปของ jQuery เช่น->children()
และ->text()
และโดยเฉพาะอย่างยิ่ง->attr()
ช่วยลดความซับซ้อนในการดึงข้อมูลโค้ด HTML ที่ถูกต้อง (และมีการถอดรหัสเอนทิตี SGML แล้ว)
$qp->xpath("//div/p[1]"); // get first paragraph in a div
QueryPath ยังอนุญาตให้ฉีดแท็กใหม่ลงในสตรีม ( ->append
) และเอาต์พุตในภายหลังและเตรียมเอกสารที่อัปเดตไว้->writeHTML
ล่วงหน้า( ) ไม่เพียง แต่สามารถแยกวิเคราะห์ HTML ที่มีรูปแบบไม่ถูกต้อง แต่ยังรวมถึงภาษาถิ่น XML ต่างๆ (พร้อมเนมสเปซ) และยังดึงข้อมูลจากไมโครฟอร์แมต HTML (XFN, vCard)
$qp->find("a[target=_blank]")->toggleClass("usability-blunder");
.
phpQuery หรือ QueryPath?
โดยทั่วไป QueryPath เหมาะสำหรับการจัดการเอกสาร ในขณะที่ phpQuery ยังใช้วิธีการหลอก AJAX (เฉพาะคำขอ HTTP) เพื่อให้คล้ายกับ jQuery มากขึ้น ว่ากันว่า phpQuery มักจะเร็วกว่า QueryPath (เนื่องจากคุณสมบัติโดยรวมน้อยกว่า)
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับความแตกต่างที่เห็นการเปรียบเทียบนี้บนเครื่อง Wayback จาก tagbyte.org (แหล่งที่มาดั้งเดิมหายไปดังนั้นนี่คือลิงก์ที่เก็บถาวรทางอินเทอร์เน็ตใช่คุณยังคงสามารถค้นหาหน้าที่หายไปผู้คนได้)
และนี่คือการแนะนำ QueryPath ครอบคลุม
ข้อดี
- ความเรียบง่ายและความน่าเชื่อถือ
- ทางเลือกที่ใช้งานง่าย
->find("a img, a object, div a")
- การไม่ใช้ Escape ข้อมูลที่เหมาะสม (เมื่อเปรียบเทียบกับการดึงนิพจน์ทั่วไป)
Simple HTML DOM เป็นตัวแยกวิเคราะห์โอเพนซอร์สที่ยอดเยี่ยม:
simplehtmldom.sourceforge
มันปฏิบัติต่อองค์ประกอบ DOM ในลักษณะเชิงวัตถุและการทำซ้ำใหม่มีความครอบคลุมจำนวนมากสำหรับโค้ดที่ไม่เป็นไปตามข้อกำหนด นอกจากนี้ยังมีฟังก์ชันที่ยอดเยี่ยมบางอย่างเช่นที่คุณเห็นใน JavaScript เช่นฟังก์ชัน "find" ซึ่งจะส่งคืนอินสแตนซ์ทั้งหมดขององค์ประกอบของชื่อแท็กนั้น
ฉันใช้สิ่งนี้ในเครื่องมือหลายอย่างทดสอบกับหน้าเว็บหลายประเภทและฉันคิดว่ามันใช้งานได้ดี
วิธีการทั่วไปอย่างหนึ่งที่ฉันไม่ได้กล่าวถึงในที่นี้คือการเรียกใช้ HTML ผ่านTidyซึ่งสามารถตั้งค่าให้คาย XHTML ที่รับประกันได้ จากนั้นคุณสามารถใช้ไลบรารี XML เก่าใดก็ได้
แต่สำหรับปัญหาเฉพาะของคุณคุณควรดูโครงการนี้: http://fivefilters.org/content-only/- เป็นเวอร์ชันแก้ไขของอัลกอริทึมการอ่านซึ่งออกแบบมาเพื่อแยกเฉพาะเนื้อหาที่เป็นข้อความ (ไม่ใช่ส่วนหัวและส่วนท้าย) จากหน้า
สำหรับ 1a และ 2: ฉันจะโหวตให้ Symfony Componet คลาส DOMCrawler ( DomCrawler ) ใหม่ คลาสนี้อนุญาตให้มีการสืบค้นคล้ายกับ CSS Selectors ลองดูที่นำเสนอนี้สำหรับตัวอย่างจริงของโลก: ข่าวของ symfony2 โลก
ส่วนประกอบได้รับการออกแบบให้ทำงานแบบสแตนด์อโลนและสามารถใช้งานได้โดยไม่ต้องใช้ Symfony
ข้อเสียเปรียบเพียงอย่างเดียวคือจะใช้งานได้กับ PHP 5.3 หรือใหม่กว่าเท่านั้น
นี้เป็นที่นิยมเรียกว่าขูดหน้าจอโดยวิธีการ ห้องสมุดที่ฉันได้ใช้สำหรับเรื่องนี้คือHTML อย่างง่าย Dom Parser
เราได้สร้างโปรแกรมรวบรวมข้อมูลสำหรับความต้องการของเรามาก่อนแล้ว ในตอนท้ายของวันมักจะเป็นนิพจน์ทั่วไปที่เรียบง่ายซึ่งทำให้สิ่งนั้นดีที่สุด แม้ว่าไลบรารีที่ระบุไว้ข้างต้นจะดีสำหรับเหตุผลที่สร้างขึ้นหากคุณรู้ว่าคุณกำลังมองหาอะไรนิพจน์ทั่วไปเป็นวิธีที่ปลอดภัยกว่าเนื่องจากคุณสามารถจัดการกับโครงสร้างHTML / XHTML ที่ไม่ถูกต้องซึ่งอาจล้มเหลวหากโหลด ผ่านตัววิเคราะห์ส่วนใหญ่
ผมขอแนะนำให้PHP ง่าย HTML DOM Parser
มีคุณสมบัติที่ดีจริงๆเช่น:
foreach($html->find('img') as $element)
echo $element->src . '<br>';
ฟังดูเหมือนคำอธิบายงานที่ดีของเทคโนโลยีW3C XPath ง่ายต่อการแสดงข้อความค้นหาเช่น "ส่งคืนhref
แอตทริบิวต์ทั้งหมดในimg
แท็กที่ซ้อนอยู่<foo><bar><baz> elements
" ไม่ได้เป็นคนชอบ PHP ฉันไม่สามารถบอกคุณได้ว่า XPath สามารถใช้ได้ในรูปแบบใด หากคุณสามารถเรียกโปรแกรมภายนอกเพื่อประมวลผลไฟล์ HTML คุณควรจะสามารถใช้ XPath เวอร์ชันบรรทัดคำสั่งได้ สำหรับคำแนะนำสั้น ๆ โปรดดูhttp://en.wikipedia.org/wiki/XPath.
ทางเลือกบุคคลที่สามเพื่อ SimpleHtmlDom ว่าการใช้ DOM แทน String แยก: phpQuery , Zend_Dom , QueryPathและFluentDom
ได้คุณสามารถใช้ simple_html_dom ตามวัตถุประสงค์ อย่างไรก็ตามฉันได้ทำงานกับ simple_html_dom มามากแล้วโดยเฉพาะอย่างยิ่งสำหรับการลบเว็บและพบว่ามีช่องโหว่เกินไป มันเป็นงานพื้นฐาน แต่ฉันจะไม่แนะนำมันอีกต่อไป
ฉันไม่เคยใช้ curl เพื่อจุดประสงค์ แต่สิ่งที่ฉันได้เรียนรู้คือ curl สามารถทำงานได้อย่างมีประสิทธิภาพและมั่นคงกว่ามาก
โปรดตรวจสอบลิงก์นี้: การขูดเว็บไซต์ด้วยการม้วนงอ
QueryPathเป็นสิ่งที่ดี แต่โปรดระวัง "สถานะการติดตาม" หากคุณไม่ทราบว่ามันหมายถึงอะไรอาจหมายความว่าคุณเสียเวลาในการดีบักจำนวนมากในการพยายามค้นหาว่าเกิดอะไรขึ้นและทำไมโค้ดจึงไม่ทำงาน
ความหมายคือการเรียกแต่ละครั้งในชุดผลลัพธ์จะแก้ไขผลลัพธ์ที่ตั้งไว้ในออบเจ็กต์ซึ่งไม่สามารถเชื่อมโยงกันได้เหมือนใน jquery ที่แต่ละลิงก์เป็นชุดใหม่คุณมีชุดเดียวซึ่งเป็นผลลัพธ์จากการสืบค้นของคุณและการเรียกใช้ฟังก์ชันแต่ละครั้งจะแก้ไข ชุดเดียว
เพื่อให้ได้พฤติกรรมที่เหมือน jquery คุณต้องแตกแขนงก่อนที่จะทำการกรอง / แก้ไขการดำเนินการเช่นนั้นหมายความว่ามันจะสะท้อนสิ่งที่เกิดขึ้นใน jquery อย่างใกล้ชิด
$results = qp("div p"); $forename = $results->find("input[name='forename']");
$results
ตอนนี้มีชุดผลลัพธ์สำหรับinput[name='forename']
ไม่ใช่แบบสอบถามดั้งเดิม"div p"
ซึ่งทำให้ฉันสะดุดมากสิ่งที่ฉันพบคือQueryPathติดตามตัวกรองและค้นหาและทุกสิ่งที่แก้ไขผลลัพธ์ของคุณและเก็บไว้ในวัตถุ คุณต้องทำสิ่งนี้แทน
$forename = $results->branch()->find("input[name='forname']")
จากนั้น$results
จะไม่ถูกแก้ไขและคุณสามารถใช้ชุดผลลัพธ์ซ้ำแล้วซ้ำอีกบางทีคนที่มีความรู้มากกว่านี้ก็สามารถล้างสิ่งนี้ได้เล็กน้อย แต่โดยพื้นฐานแล้วมันเป็นแบบนี้จากสิ่งที่ฉันพบ
Advanced Html Domเป็นการแทนที่HTML DOMแบบง่ายๆที่มีอินเทอร์เฟซเดียวกัน แต่เป็นแบบ DOM ซึ่งหมายความว่าไม่มีปัญหาหน่วยความจำที่เกี่ยวข้องเกิดขึ้น
นอกจากนี้ยังรองรับ CSS เต็มรูปแบบรวมถึงส่วนขยายjQuery
สำหรับHTML5 html5 lib ถูกทิ้งร้างมาหลายปีแล้ว ไลบรารี HTML5 เดียวที่ฉันสามารถพบได้จากการอัปเดตล่าสุดและบันทึกการบำรุงรักษาคือhtml5-phpซึ่งเพิ่งนำมาสู่เบต้า 1.0 เมื่อสัปดาห์ก่อน
ฉันสร้างไลบรารีชื่อPHPPowertools / DOM-Queryซึ่งช่วยให้คุณสามารถรวบรวมข้อมูลเอกสาร HTML5 และ XML ได้เช่นเดียวกับที่คุณทำกับ jQuery
ภายใต้ประทุนจะใช้symfony / DomCrawlerสำหรับการแปลงเตอร์ CSS เพื่อXPathเตอร์ มันจะใช้ DomDocument เดียวกันเสมอแม้ว่าจะส่งผ่านอ็อบเจกต์หนึ่งไปยังอีกอ็อบเจกต์หนึ่งเพื่อให้แน่ใจว่ามีประสิทธิภาพที่ดี
ตัวอย่างการใช้งาน:
namespace PowerTools;
// Get file content
$htmlcode = file_get_contents('https://github.com'); // Define your DOMCrawler based on file string $H = new DOM_Query($htmlcode); // Define your DOMCrawler based on an existing DOM_Query instance $H = new DOM_Query($H->select('body')); // Passing a string (CSS selector) $s = $H->select('div.foo'); // Passing an element object (DOM Element) $s = $H->select($documentBody);
// Passing a DOM Query object
$s = $H->select( $H->select('p + p')); // Select the body tag $body = $H->select('body'); // Combine different classes as one selector to get all site blocks $siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer'); // Nest your methods just like you would with jQuery $siteblocks->select('button')->add('span')->addClass('icon icon-printer');
// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) { return $i . " - " . $val->attr('class'); }); // Append the following HTML to all site blocks $siteblocks->append('<div class="site-center"></div>');
// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');
// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see')); // Use a lambda function to set the attributes of all site blocks $siteblocks->attr('data-val', function( $i, $val) {
return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
});
// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();
// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class'); // Wrap the site's footer within two nex selectors $sitefooter->wrap('<section><div class="footer-wrapper"></div></section>');
[...]
วิธีการที่รองรับ:
- [x] $ (1)
- [x] $ .parseHTML
- [x] $ .parseXML
- [x] $ .parseJSON
- [x] $ selection.add
- [x] $ selection.addClass
- [x] $ selection.after
- [x] $ selection.append
- [x] $ selection.attr
- [x] $ selection.before
- [x] $ selection.children
- [x] $ selection.closest
- [x] $ selection.contents
- [x] $ selection.detach
- [x] $ selection แต่ละ
- [x] $ selection.eq
- [x] $ selection.empty (2)
- [x] $ selection.find
- [x] $ selection.first
- [x] $ selection.get
- [x] $ selection.insertAfter
- [x] $ selection.insertBefore
- [x] $ selection.last
- [x] $ selection.parent
- [x] $ selection.parents
- [x] $ selection.remove
- [x] $ selection.removeAttr
- [x] $ selection.removeClass
- [x] $ selection.text
- [x] $ selection.wrap
- เปลี่ยนชื่อเป็น "เลือก" ด้วยเหตุผลที่ชัดเจน
- เปลี่ยนชื่อเป็น 'void' เนื่องจาก 'ว่าง' เป็นคำสงวนใน PHP
บันทึก :
ไลบรารียังมีตัวโหลดอัตโนมัติแบบกำหนดค่าเป็นศูนย์สำหรับไลบรารีที่เข้ากันได้กับ PSR-0 ตัวอย่างที่รวมควรใช้งานได้ทันทีโดยไม่ต้องกำหนดค่าเพิ่มเติมใด ๆ หรือคุณสามารถใช้ร่วมกับนักแต่งเพลง
ฉันได้เขียนตัวแยกวิเคราะห์ XML สำหรับวัตถุประสงค์ทั่วไปที่สามารถจัดการไฟล์ GB ได้อย่างง่ายดาย มันขึ้นอยู่กับ XMLReader และใช้งานง่ายมาก:
$source = new XmlExtractor("path/to/tag", "/path/to/file.xml"); foreach ($source as $tag) { echo $tag->field1;
echo $tag->field2->subfield1;
}
นี่คือ repo github: XmlExtractor
ตัวเลือกที่คุณสามารถลองก็คือQueryPath มันเป็นแรงบันดาลใจจาก jQuery แต่บนเซิร์ฟเวอร์ใน PHP และใช้ในDrupal
คุณสามารถลองใช้HTML Tidyเพื่อล้าง HTML ที่ "เสีย" และแปลง HTML เป็น XHTML ซึ่งคุณสามารถแยกวิเคราะห์ด้วยตัวแยกวิเคราะห์ XML ได้
XML_HTMLSaxค่อนข้างคงที่ - แม้ว่าจะไม่ได้รับการดูแลอีกต่อไปก็ตาม อีกทางเลือกหนึ่งคือการไพพ์ HTML ของคุณผ่านHtml Tidyจากนั้นแยกวิเคราะห์ด้วยเครื่องมือ XML มาตรฐาน
มีหลายวิธีในการประมวลผล HTML / XML DOM ซึ่งส่วนใหญ่ได้รับการกล่าวถึงแล้ว ดังนั้นฉันจะไม่พยายามทำรายการเหล่านั้นด้วยตัวเอง
ฉันแค่ต้องการเพิ่มว่าฉันชอบใช้ส่วนขยาย DOM เป็นการส่วนตัวและทำไม:
- iit ใช้ประโยชน์จากข้อได้เปรียบด้านประสิทธิภาพของรหัส C ที่อยู่เบื้องหลังให้เกิดประโยชน์สูงสุด
- มันเป็น OO PHP (และช่วยให้ฉันสามารถ subclass ได้)
- ค่อนข้างต่ำ (ซึ่งช่วยให้ฉันใช้เป็นพื้นฐานที่ไม่ป่องสำหรับพฤติกรรมขั้นสูง)
- ให้การเข้าถึงทุกส่วนของ DOM (ไม่เหมือนเช่น SimpleXml ซึ่งละเว้นคุณสมบัติ XML ที่รู้จักน้อยกว่า)
- มีไวยากรณ์ที่ใช้สำหรับการรวบรวมข้อมูล DOM ที่คล้ายกับไวยากรณ์ที่ใช้ใน Javascript ดั้งเดิม
และในขณะที่ฉันพลาดความสามารถในการใช้ตัวเลือก CSS สำหรับDOMDocument
แต่ก็มีวิธีที่ค่อนข้างง่ายและสะดวกในการเพิ่มคุณสมบัตินี้: คลาสย่อยDOMDocument
และเพิ่ม JS-like querySelectorAll
และquerySelector
วิธีการในคลาสย่อย
สำหรับการแยกเตอร์ผมขอแนะนำให้ใช้ minimalistic มากองค์ประกอบ CssSelectorจากกรอบ Symfony คอมโพเนนต์นี้เพียงแค่แปลตัวเลือก CSS เป็นตัวเลือก XPath ซึ่งสามารถป้อนลงใน a DOMXpath
เพื่อดึง Nodelist ที่เกี่ยวข้องได้
จากนั้นคุณสามารถใช้คลาสย่อยนี้ (ยังอยู่ในระดับต่ำมาก) เป็นพื้นฐานสำหรับคลาสระดับสูงขึ้นโดยมีจุดประสงค์เพื่อเช่น แยกวิเคราะห์ประเภทของ XML ที่เฉพาะเจาะจงมากหรือเพิ่มพฤติกรรมที่เหมือน jQuery มากขึ้น
โค้ดด้านล่างแสดงให้เห็นไลบรารี DOM-Queryของฉันโดยตรงและใช้เทคนิคที่ฉันอธิบายไว้
สำหรับการแยกวิเคราะห์ HTML:
namespace PowerTools;
use \Symfony\Component\CssSelector\CssSelector as CssSelector;
class DOM_Document extends \DOMDocument {
public function __construct($data = false, $doctype = 'html', $encoding = 'UTF-8', $version = '1.0') {
parent::__construct($version, $encoding);
if ($doctype && $doctype === 'html') {
@$this->loadHTML($data);
} else {
@$this->loadXML($data);
}
}
public function querySelectorAll($selector, $contextnode = null) {
if (isset($this->doctype->name) && $this->doctype->name == 'html') {
CssSelector::enableHtmlExtension();
} else {
CssSelector::disableHtmlExtension();
}
$xpath = new \DOMXpath($this);
return $xpath->query(CssSelector::toXPath($selector, 'descendant::'), $contextnode); } [...] public function loadHTMLFile($filename, $options = 0) { $this->loadHTML(file_get_contents($filename), $options);
}
public function loadHTML($source, $options = 0) {
if ($source && $source != '') {
$data = trim($source);
$html5 = new HTML5(array('targetDocument' => $this, 'disableHtmlNsInDom' => true));
$data_start = mb_substr($data, 0, 10);
if (strpos($data_start, '<!DOCTYPE ') === 0 || strpos($data_start, '<html>') === 0) {
$html5->loadHTML($data);
} else {
@$this->loadHTML('<!DOCTYPE html><html><head><meta charset="' . $encoding . '" /></head><body></body></html>');
$t = $html5->loadHTMLFragment($data); $docbody = $this->getElementsByTagName('body')->item(0); while ($t->hasChildNodes()) {
$docbody->appendChild($t->firstChild);
}
}
}
}
[...]
}
ดูการแยกวิเคราะห์เอกสาร XML ด้วยตัวเลือก CSSโดย Fabien Potencier ผู้สร้างของ Symfony เกี่ยวกับการตัดสินใจสร้างคอมโพเนนต์ CssSelector สำหรับ Symfony และวิธีการใช้งาน
Symfonyกรอบมีการรวมกลุ่มซึ่งสามารถแยก HTML และคุณสามารถใช้รูปแบบ CSS เพื่อเลือกถุงยางแทนการใช้XPath
ด้วยFluidXMLคุณสามารถสอบถามและสำทับ XML ใช้XPathและCSS Selectors
$doc = fluidxml('<html>...</html>'); $title = $doc->query('//head/title')[0]->nodeValue; $doc->query('//body/p', 'div.active', '#bgId')
->each(function($i, $node) {
// $node is a DOMNode. $tag = $node->nodeName; $text = $node->nodeValue; $class = $node->getAttribute('class');
});
https://github.com/servo-php/fluidxml
JSON และอาร์เรย์จาก XML ในสามบรรทัด:
$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
ตาดา!
มีสาเหตุหลายประการที่จะไม่แยกวิเคราะห์ HTML ด้วยนิพจน์ทั่วไป แต่ถ้าคุณสามารถควบคุมสิ่งที่จะสร้าง HTML ได้ทั้งหมดคุณสามารถทำได้ด้วยนิพจน์ทั่วไปง่ายๆ
ด้านบนเป็นฟังก์ชันที่แยกวิเคราะห์ HTML ด้วยนิพจน์ทั่วไป โปรดทราบว่าฟังก์ชันนี้มีความละเอียดอ่อนมากและต้องการให้ HTML ปฏิบัติตามกฎบางอย่าง แต่ก็ใช้ได้ดีในหลายสถานการณ์ หากคุณต้องการตัวแยกวิเคราะห์ที่เรียบง่ายและไม่ต้องการติดตั้งไลบรารีลองดูสิ่งนี้:
function array_combine_($keys, $values) {
$result = array(); foreach ($keys as $i => $k) {
$result[$k][] = $values[$i];
}
array_walk($result, create_function('&$v', '$v = (count($v) == 1)? array_pop($v): $v;'));
return $result; } function extract_data($str) {
return (is_array($str)) ? array_map('extract_data', $str)
: ((!preg_match_all('#<([A-Za-z0-9_]*)[^>]*>(.*?)</\1>#s', $str, $matches))
? $str : array_map(('extract_data'), array_combine_($matches[1], $matches[2])));
}
print_r(extract_data(file_get_contents("http://www.google.com/")));
ฉันได้สร้างไลบรารีชื่อ HTML5DOMDocument ซึ่งสามารถใช้ได้ฟรีที่ https://github.com/ivopetkov/html5-dom-document-php
มันสนับสนุนตัวเลือกการค้นหาด้วยซึ่งฉันคิดว่าจะเป็นประโยชน์อย่างยิ่งในกรณีของคุณ นี่คือตัวอย่างโค้ด:
$dom = new IvoPetkov\HTML5DOMDocument(); $dom->loadHTML('<!DOCTYPE html><html><body><h1>Hello</h1><div class="content">This is some text</div></body></html>');
echo $dom->querySelector('h1')->innerHTML;
หากคุณคุ้นเคยกับ jQuery selector คุณสามารถใช้ScarletsQueryสำหรับ PHP ได้
<pre><?php
include "ScarletsQuery.php";
// Load the HTML content and parse it
$html = file_get_contents('https://www.lipsum.com'); $dom = Scarlets\Library\MarkupLanguage::parseText($html); // Select meta tag on the HTML header $description = $dom->selector('head meta[name="description"]')[0]; // Get 'content' attribute value from meta tag print_r($description->attr('content'));
$description = $dom->selector('#Content p');
// Get element array
print_r($description->view);
โดยปกติไลบรารีนี้จะใช้เวลาน้อยกว่า 1 วินาทีในการประมวลผล html แบบออฟไลน์
นอกจากนี้ยังยอมรับ HTML ที่ไม่ถูกต้องหรือไม่มีเครื่องหมายคำพูดสำหรับแอตทริบิวต์แท็ก
วิธีที่ดีที่สุดในการแยกวิเคราะห์ xml:
$xml='http://www.example.com/rss.xml'; $rss = simplexml_load_string($xml); $i = 0;
foreach ($rss->channel->item as $feedItem) {
$i++; echo $title=$feedItem->title; echo '<br>'; echo $link=$feedItem->link; echo '<br>'; if($feedItem->description !='') {
$des=$feedItem->description;
} else {
$des=''; } echo $des;
echo '<br>';
if($i>5) break;
}