วิธีแยกวิเคราะห์ HTML / XML และแยกข้อมูลจากมันได้อย่างไร
วิธีแยกวิเคราะห์ HTML / XML และแยกข้อมูลจากมันได้อย่างไร
คำตอบ:
ฉันชอบใช้ส่วนขยาย XML เนทิฟตัวใดตัวหนึ่งเนื่องจากมันมาพร้อมกับ PHP โดยปกติแล้วจะเร็วกว่า libs ของบุคคลที่สามทั้งหมดและให้การควบคุมทั้งหมดที่ฉันต้องการกับมาร์กอัป
ส่วนขยาย DOM ช่วยให้คุณทำงานบนเอกสาร XML ผ่าน DOM API กับ PHP 5 เป็นการดำเนินการของ Document Object Model Core ระดับ 3 ของ W3C ซึ่งเป็นส่วนต่อประสานระหว่างแพลตฟอร์มและภาษาที่ช่วยให้โปรแกรมและสคริปต์สามารถเข้าถึงและอัปเดตแบบไดนามิกได้ เนื้อหาโครงสร้างและรูปแบบของเอกสาร
DOM มีความสามารถในการแยกวิเคราะห์และแก้ไข HTML ในโลกแห่งความจริง (แตก) และสามารถทำการสืบค้น XPathได้ มันขึ้นอยู่กับlibxml
ต้องใช้เวลาพอสมควรเพื่อให้เกิดผลกับ DOM แต่เวลานั้นคุ้มค่ากับ IMO เนื่องจาก DOM เป็นอินเทอร์เฟซที่ไม่เชื่อเรื่องภาษาคุณจะพบการใช้งานในหลายภาษาดังนั้นหากคุณต้องการเปลี่ยนภาษาการเขียนโปรแกรมของคุณโอกาสที่คุณจะรู้วิธีใช้ DOM API ของภาษานั้นอยู่แล้ว
ตัวอย่างการใช้งานพื้นฐานสามารถพบได้ในGrabbing แอตทริบิวต์ href ขององค์ประกอบ Aและภาพรวมแนวคิดทั่วไปสามารถพบได้ที่DOMDocument ใน php
วิธีการใช้ส่วนขยาย DOM ได้รับการครอบคลุมอย่างกว้างขวางใน StackOverflowดังนั้นหากคุณเลือกที่จะใช้งานคุณสามารถมั่นใจได้ว่าปัญหาส่วนใหญ่ที่คุณพบสามารถแก้ไขได้ด้วยการค้นหา / เรียกดู Stack Overflow
ส่วนขยาย XMLReader เป็นตัวแยกวิเคราะห์ XML ตัวอ่านทำหน้าที่เป็นเคอร์เซอร์ไปข้างหน้าในกระแสข้อมูลเอกสารและหยุดที่แต่ละโหนดระหว่างทาง
XMLReader เช่น DOM ขึ้นอยู่กับ libxml ฉันไม่ทราบวิธีเรียกใช้โมดูลตัวแยกวิเคราะห์ HTML ดังนั้นโอกาสในการใช้ XMLReader สำหรับการแยกวิเคราะห์ HTML ที่ใช้งานไม่ได้อาจมีประสิทธิภาพน้อยกว่าการใช้ DOM ซึ่งคุณสามารถบอกให้ใช้โมดูล Parser HTML ของ libxml ได้อย่างชัดเจน
ตัวอย่างการใช้งานพื้นฐานสามารถดูได้ที่การรับค่าทั้งหมดจากแท็ก h1 โดยใช้ php
ส่วนขยายนี้ให้คุณสร้างตัวแยกวิเคราะห์ XML จากนั้นกำหนดตัวจัดการสำหรับเหตุการณ์ XML ที่แตกต่างกัน ตัวแยกวิเคราะห์ XML แต่ละตัวยังมีพารามิเตอร์บางอย่างที่คุณสามารถปรับได้
ไลบรารี XML Parser ยังใช้ libxml และใช้ตัวแยกวิเคราะห์แบบพุชแบบ XML ของSAX มันอาจเป็นทางเลือกที่ดีกว่าสำหรับการจัดการหน่วยความจำกว่า DOM หรือ SimpleXML แต่จะทำงานได้ยากกว่าการใช้ parser แบบดึงซึ่งดำเนินการโดย XMLReader
ส่วนขยาย SimpleXML มอบชุดเครื่องมือที่ง่ายและใช้งานได้ง่ายเพื่อแปลง XML เป็นวัตถุที่สามารถประมวลผลด้วยตัวเลือกคุณสมบัติปกติและตัววนซ้ำอาร์เรย์
SimpleXML เป็นตัวเลือกเมื่อคุณรู้ว่า HTML นั้นถูกต้อง XHTML หากคุณจำเป็นต้องแยกวิเคราะห์ HTML ที่เสียหายอย่าพิจารณาแม้แต่ SimpleXml เพราะจะทำให้หายใจไม่ออก
ตัวอย่างการใช้งานพื้นฐานสามารถพบได้ที่โปรแกรมที่ง่ายต่อ CRUD โหนดและโหนดค่าของไฟล์ XMLและมีจำนวนมากตัวอย่างเพิ่มเติมในคู่มือการใช้งานของ PHP
หากคุณต้องการใช้ lib บุคคลที่สามฉันขอแนะนำให้ใช้ lib ที่ใช้DOM / libxmlด้านล่างแทนการแยกสตริง
FluentDOM ให้บริการอินเตอร์เฟส XML ที่คล้ายกับ jQuery สำหรับ DOMDocument ใน PHP Selectors ถูกเขียนใน XPath หรือ CSS (ใช้ตัวแปลง CSS เป็น XPath) เวอร์ชันปัจจุบันขยายการใช้งานอินเทอร์เฟซมาตรฐานของ DOM และเพิ่มคุณสมบัติจาก DOM Living Standard FluentDOM สามารถโหลดรูปแบบเช่น JSON, CSV, JsonML, RabbitFish และอื่น ๆ สามารถติดตั้งผ่าน Composer
Wa72 \ HtmlPageDom` เป็นไลบรารี PHP สำหรับการจัดการเอกสาร HTML ที่ใช้งานง่ายโดยต้องใช้DomCrawler จากคอมโพเนนต์ Symfony2สำหรับการสำรวจทรี DOM และขยายโดยเพิ่มวิธีการจัดการ Tree DOM ของเอกสาร HTML
phpQuery เป็นฝั่งเซิร์ฟเวอร์, ตัวเลือก CSS3 ซึ่งเป็นตัวขับเคลื่อน CSS3 ซึ่งเป็นตัวขับเคลื่อนเอกสารที่ขับเคลื่อนด้วย API บนพื้นฐานของ jQuery JavaScript Library ที่เขียนด้วย PHP5 และให้ Command Line Interface (CLI) เพิ่มเติม
ดูเพิ่มเติมที่: https://github.com/electrolinux/phpquery
Zend_Dom จัดเตรียมเครื่องมือสำหรับการทำงานกับเอกสารและโครงสร้าง DOM ขณะนี้เราขอเสนอ Zend_Dom_Query ซึ่งมีอินเทอร์เฟซแบบรวมสำหรับการสืบค้นเอกสาร DOM ที่ใช้ทั้งตัวเลือก XPath และ CSS
QueryPath เป็นห้องสมุด PHP สำหรับจัดการ XML และ HTML มันถูกออกแบบมาเพื่อทำงานไม่เพียง แต่กับไฟล์ในเครื่อง แต่ยังมีบริการบนเว็บและทรัพยากรฐานข้อมูล มันใช้อินเตอร์เฟซ jQuery เป็นส่วนใหญ่ (รวมถึงตัวเลือกสไตล์ CSS) แต่ได้รับการปรับแต่งอย่างมากสำหรับการใช้งานฝั่งเซิร์ฟเวอร์ สามารถติดตั้งผ่าน Composer
fDOMDocument ขยาย DOM มาตรฐานเพื่อใช้ข้อยกเว้นในทุกโอกาสที่เกิดข้อผิดพลาดแทนคำเตือนหรือประกาศ PHP พวกเขายังเพิ่มวิธีการที่กำหนดเองและทางลัดต่าง ๆ เพื่อความสะดวกและเพื่อให้การใช้ DOM ง่ายขึ้น
saber / xml เป็นไลบรารีที่ล้อมรอบและขยายคลาส XMLReader และ XMLWriter เพื่อสร้างระบบการแมป "xml to object / array" แบบง่ายและรูปแบบการออกแบบ การเขียนและอ่าน XML เป็นแบบผ่านครั้งเดียวและสามารถรวดเร็วและต้องการหน่วยความจำเหลือน้อยในไฟล์ xml ขนาดใหญ่
FluidXML เป็นห้องสมุด PHP สำหรับจัดการ XML ด้วย API ที่กระชับและคล่องแคล่ว มันใช้ประโยชน์จาก XPath และรูปแบบการเขียนโปรแกรมได้อย่างคล่องแคล่วเพื่อความสนุกสนานและมีประสิทธิภาพ
ประโยชน์ของการสร้างจาก DOM / libxml คือคุณได้รับประสิทธิภาพการทำงานที่ดีเพราะคุณใช้ส่วนขยายแบบเนทีฟ อย่างไรก็ตามไม่ใช่ libs บุคคลที่สามทั้งหมดที่ลงเส้นทางนี้ บางคนอยู่ด้านล่าง
- เครื่องมือแยกวิเคราะห์ HTML DOM ที่เขียนด้วย PHP5 + ช่วยให้คุณจัดการ HTML ได้อย่างง่ายดาย!
- ต้องการ PHP 5+
- รองรับ HTML ที่ไม่ถูกต้อง
- ค้นหาแท็กในหน้า HTML ที่มีตัวเลือกเช่นเดียวกับ jQuery
- แยกเนื้อหาจาก HTML ในบรรทัดเดียว
ฉันไม่แนะนำให้ใช้เครื่องมือแยกวิเคราะห์นี้ codebase นั้นแย่มากและ parser นั้นค่อนข้างช้าและหน่วยความจำก็หิว ไม่สามารถเลือก jQuery Selectors ทั้งหมด (เช่นตัวเลือกลูก ) ได้ ไลบรารีที่ใช้ libxml ควรมีประสิทธิภาพสูงกว่านี้อย่างง่ายดาย
PHPHtmlParser เป็นตัวแยกวิเคราะห์ html ที่เรียบง่ายยืดหยุ่นซึ่งอนุญาตให้คุณเลือกแท็กโดยใช้ตัวเลือก css เช่น jQuery เป้าหมายคือช่วยในการพัฒนาเครื่องมือที่ต้องการวิธีที่ง่ายและรวดเร็วในการคัดลอก html ไม่ว่าจะถูกต้องหรือไม่ก็ตาม! โครงการนี้ได้รับการสนับสนุนดั้งเดิมโดย sunra / php-simple-html-dom-parser แต่การสนับสนุนดูเหมือนจะหยุดลงดังนั้นโครงการนี้คือการปรับตัวของงานก่อนหน้านี้ของฉัน
อีกครั้งฉันจะไม่แนะนำ parser นี้ ค่อนข้างช้าด้วยการใช้งาน CPU สูง นอกจากนี้ยังไม่มีฟังก์ชั่นเพื่อล้างหน่วยความจำของวัตถุ DOM ที่สร้างขึ้น ปัญหาเหล่านี้ขยายขอบเขตโดยเฉพาะอย่างยิ่งกับลูปซ้อนกัน เอกสารนั้นไม่ถูกต้องและสะกดผิดโดยไม่มีการตอบกลับการแก้ไขตั้งแต่วันที่ 14 เม.ย. 16
- โทเค็นอเนกประสงค์และตัวแยก DOM DOM HTML / XML / RSS
- ความสามารถในการจัดการองค์ประกอบและคุณสมบัติของพวกเขา
- รองรับ HTML และ UTF8 ที่ไม่ถูกต้อง
- สามารถดำเนินการแบบสอบถาม CSS3 เหมือนขั้นสูงในองค์ประกอบ (เช่น jQuery - รองรับ namespaces)
- เครื่องมือตกแต่ง HTML (เช่น HTML Tidy)
- ลดขนาด CSS และ Javascript
- จัดเรียงแอตทริบิวต์เปลี่ยนตัวอักษรกรณีการเยื้องที่ถูกต้อง ฯลฯ
- Extensible
- การแยกเอกสารโดยใช้การเรียกกลับตามอักขระ / โทเค็นปัจจุบัน
- การดำเนินการแยกกันในฟังก์ชั่นขนาดเล็กเพื่อการเอาชนะได้ง่าย
- ง่ายและรวดเร็ว
ไม่เคยใช้มัน ไม่สามารถบอกได้ว่ามันดีหรือไม่
คุณสามารถใช้ด้านบนสำหรับการแยกวิเคราะห์ HTML5 แต่อาจมีข้อผิดพลาดเนื่องจากมาร์กอัพ HTML5 อนุญาต ดังนั้นสำหรับ HTML5 คุณต้องการพิจารณาใช้ parser เฉพาะเช่น
การใช้งาน Python และ PHP ของตัวแยกวิเคราะห์ HTML ตามข้อกำหนด WHATWG HTML5 เพื่อความเข้ากันได้สูงสุดกับเว็บเบราว์เซอร์เดสก์ท็อปหลัก
เราอาจเห็นตัวแยกวิเคราะห์เฉพาะเพิ่มเติมเมื่อ HTML5 ได้รับการสรุป นอกจากนี้ยังมีบล็อกโพสต์โดย W3 ชื่อว่าHow-To สำหรับการแยกวิเคราะห์ HTML 5ที่ควรค่าแก่การตรวจสอบ
หากคุณไม่ต้องการเขียนโปรแกรม PHP คุณสามารถใช้บริการเว็บได้ โดยทั่วไปแล้วฉันพบยูทิลิตี้น้อยมากสำหรับสิ่งเหล่านี้ แต่นั่นเป็นเพียงฉันและกรณีใช้งานของฉัน
อินเทอร์เฟซภายนอกของ ScraperWiki ช่วยให้คุณสามารถดึงข้อมูลในแบบฟอร์มที่คุณต้องการใช้บนเว็บหรือในแอปพลิเคชันของคุณเอง คุณยังสามารถดึงข้อมูลเกี่ยวกับสถานะของมีดโกนใด ๆ
ที่ผ่านมาและน้อยแนะนำให้คุณสามารถดึงข้อมูลจาก HTML ที่มีการแสดงออกปกติ โดยทั่วไปแล้วไม่สนับสนุนการใช้นิพจน์ปกติบน HTML
ตัวอย่างข้อมูลส่วนใหญ่ที่คุณจะพบบนเว็บเพื่อจับคู่มาร์กอัปนั้นมีความเปราะ ในกรณีส่วนใหญ่พวกเขาจะทำงานเฉพาะกับ HTML ที่เฉพาะเจาะจงเท่านั้น การเปลี่ยนแปลงมาร์กอัปเล็ก ๆ เช่นเพิ่มช่องว่างที่ไหนสักแห่งหรือเพิ่มหรือเปลี่ยนแอตทริบิวต์ในแท็กสามารถทำให้ RegEx ล้มเหลวเมื่อเขียนไม่ถูกต้อง คุณควรรู้ว่าคุณกำลังทำอะไรก่อนใช้ RegEx บน HTML
ตัวแยกวิเคราะห์ HTML รู้จักกฎการสร้างประโยคของ HTML แล้ว นิพจน์ทั่วไปจะต้องมีการสอนสำหรับ RegEx ใหม่แต่ละรายการที่คุณเขียน RegEx นั้นใช้ได้ในบางกรณี แต่ขึ้นอยู่กับการใช้งานของคุณ
คุณสามารถเขียนตัวแยกวิเคราะห์ที่เชื่อถือได้มากขึ้นแต่การเขียนตัวแยกวิเคราะห์แบบกำหนดเองที่สมบูรณ์และเชื่อถือได้ด้วยนิพจน์ทั่วไปนั้นเป็นการเสียเวลาเมื่อไลบรารีดังกล่าวมีอยู่แล้วและทำงานได้ดีขึ้นมาก
ดูที่การแยกวิเคราะห์ Html The Cthulhu Way
หากคุณต้องการใช้เงินลองดูที่
ฉันไม่ได้มีส่วนเกี่ยวข้องกับ PHP Architect หรือผู้เขียน
ลองใช้HTML DOM Parser แบบง่าย
// 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>';
// 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;
// Dump contents (without tags) from HTML
echo file_get_html('http://www.google.com/')->plaintext;
// 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 สามารถ" ดึง "ข้อมูลได้ การแยกเป็นสิ่งที่พวกเขาทำ ข้อเสียเปรียบที่สำคัญของการแยก HTML regex ผ่านชุดเครื่องมือ 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");
อย่างไรก็ตามมีกรณีการใช้งานเฉพาะที่พวกเขาสามารถช่วยได้
<!--
ซึ่งบางครั้งก็เป็นจุดยึดที่มีประโยชน์มากกว่าสำหรับการแยกไฟล์ โดยเฉพาะอย่างยิ่งรูปแบบหลอก HTML <$var>
หรือเศษ SGML นั้นง่ายต่อการเชื่องด้วย regexpsบางครั้งก็แนะนำให้แยกตัวอย่างของ HTML ล่วงหน้าโดยใช้นิพจน์ปกติ/<!--CONTENT-->(.+?)<!--END-->/
และประมวลผลส่วนที่เหลือโดยใช้ส่วนหน้า HTML parser ที่ง่ายกว่า
หมายเหตุ:ฉันมีแอพนี้จริงๆที่ฉันใช้การแยกวิเคราะห์ XML และแสดงผลปกติหรือ เมื่อสัปดาห์ที่แล้วการแยกวิเคราะห์ PyQuery หยุดชะงักและ regex ยังทำงานอยู่ ใช่แปลกและฉันไม่สามารถอธิบายได้ด้วยตนเอง แต่มันก็เกิดขึ้น
ดังนั้นโปรดอย่าโหวตให้กับการพิจารณาในโลกแห่งความจริงเพราะมันไม่ตรงกับ regex = evil meme แต่เราก็ไม่ควรลงคะแนนมากเกินไป มันเป็นเพียง sidenote สำหรับหัวข้อนี้
DOMComment
สามารถอ่านความคิดเห็นได้ดังนั้นจึงไม่มีเหตุผลที่จะใช้ Regex
DOM
ใช้libxmlและlibxml มีโมดูลตัวแยกวิเคราะห์ HTML แยกต่างหากซึ่งจะใช้เมื่อโหลด HTML ด้วยloadHTML()
ดังนั้นจึงสามารถโหลด HTML "โลกแห่งความจริง" ได้อย่างมาก (อ่านไม่ทำงาน)
phpQueryและQueryPathมีความคล้ายคลึงกันอย่างมากในการจำลอง jQuery API ได้อย่างคล่องแคล่ว นั่นเป็นเหตุผลว่าทำไมพวกเขาถึงวิธีที่ง่ายที่สุดสองวิธีในการแยกวิเคราะห์ HTML ใน PHP อย่างถูกต้อง
ตัวอย่างสำหรับ QueryPath
โดยพื้นฐานแล้วคุณสร้างทรี DOM ที่สืบค้นได้จากสตริง HTML เป็นครั้งแรก:
$qp = qp("<html><body><h1>title</h1>..."); // or give filename or URL
วัตถุที่เป็นผลลัพธ์ประกอบด้วยการแสดงทรีที่สมบูรณ์ของเอกสาร HTML มันสามารถถูก traversed โดยใช้วิธี 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
) และส่งออกในภายหลังและ prettify เอกสารที่อัปเดต ( ->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")
Simple HTML DOM เป็นโปรแกรมแยกวิเคราะห์โอเพ่นซอร์สที่ยอดเยี่ยม:
มันปฏิบัติต่อองค์ประกอบ DOM ในลักษณะเชิงวัตถุและการวนซ้ำใหม่มีความครอบคลุมมากสำหรับรหัสที่ไม่เข้ากัน นอกจากนี้ยังมีฟังก์ชั่นที่ยอดเยี่ยมเช่นที่คุณเห็นใน JavaScript เช่นฟังก์ชัน "ค้นหา" ซึ่งจะส่งคืนองค์ประกอบทั้งหมดของชื่อแท็กนั้น
ฉันใช้มันเป็นเครื่องมือจำนวนหนึ่งทดสอบกับหน้าเว็บหลายประเภทและฉันคิดว่ามันใช้งานได้ดี
วิธีการทั่วไปอย่างหนึ่งที่ฉันไม่ได้กล่าวถึงในที่นี้คือการเรียกใช้ 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 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 สามารถทำงานได้อย่างมีประสิทธิภาพมากขึ้นและแข็งแกร่งขึ้น
กรุณาตรวจสอบลิงค์นี้: scraping-sites-with-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
ฉันได้เขียนตัวแยกวิเคราะห์ 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
ฉันสร้างห้องสมุดชื่อPHPPowertools / DOM-Queryซึ่งอนุญาตให้คุณรวบรวมข้อมูลเอกสาร HTML5 และ XML เช่นเดียวกับที่คุณทำกับ jQuery
ภายใต้ประทุนนั้นจะใช้symfony / DomCrawlerสำหรับการแปลง CSS selectors เป็นXPath selectors มันมักจะใช้ 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>');
[...]
ไลบรารี่ยังมีออโต้โหลดเดอร์ที่เป็นศูนย์ของตัวเองสำหรับไลบรารีที่เข้ากันได้กับ PSR-0 ตัวอย่างที่รวมไว้ควรจะทำงานนอกกรอบโดยไม่มีการกำหนดค่าเพิ่มเติมใด ๆ หรือคุณสามารถใช้กับนักแต่งเพลง
คุณสามารถลองใช้บางสิ่งบางอย่างเช่นHTML Tidyเพื่อล้าง HTML ที่ "เสีย" และแปลง HTML เป็น XHTML ซึ่งคุณสามารถแยกวิเคราะห์ด้วยตัวแยกวิเคราะห์ XML ได้
XML_HTMLSax
ค่อนข้างเสถียร - แม้ว่าจะไม่ได้รับการบำรุงรักษาอีกต่อไป อีกทางเลือกหนึ่งคือไปป์ HTML ของคุณผ่านHtml Tidyแล้วแยกวิเคราะห์ด้วยเครื่องมือ XML มาตรฐาน
มีหลายวิธีในการประมวลผล HTML / XML DOM ซึ่งส่วนใหญ่ได้รับการกล่าวถึงแล้ว ดังนั้นฉันจะไม่พยายามแสดงตน
ฉันแค่ต้องการเพิ่มว่าโดยส่วนตัวแล้วฉันต้องการใช้ส่วนขยาย DOM และ:
และในขณะที่ฉันพลาดความสามารถในการใช้ตัวเลือก 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 และวิธีการใช้งาน
ด้วย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');
});
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 คุณสามารถใช้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;
}