Php 使用XPATH节点从产品中获取数据并将其插入表中
我正在尝试从外部网站获取产品数据,并将它们插入到特殊的表中-每个找到的节点元素都需要导入到产品表中产品的相应列中 在查找1个产品属性并将其插入表中时效果良好:Php 使用XPATH节点从产品中获取数据并将其插入表中,php,html,xpath,Php,Html,Xpath,我正在尝试从外部网站获取产品数据,并将它们插入到特殊的表中-每个找到的节点元素都需要导入到产品表中产品的相应列中 在查找1个产品属性并将其插入表中时效果良好: $product_names = $xpath->query("//div[contains(concat(' ', normalize-space(@class), ' '), ' product_description ')]/div/h3/a"); if (!is_null($product_names)) {
$product_names = $xpath->query("//div[contains(concat(' ', normalize-space(@class), ' '), ' product_description ')]/div/h3/a");
if (!is_null($product_names)) {
foreach ($product_names as $product_name) {
$nodes = $product_name->childNodes;
foreach ($nodes as $node) {
$import_product = 'INSERT INTO product_table (id, product_name) values ("","' . preg_replace('~\\s+\\S+$~', "", strip_tags(trim($node->nodeValue))) . '")';
mysql_query($import_supralift_name);
}
}
}
<pre><?php
$domDoc = <<<EOF
<div class="single_product">
<div data-section="featured_image">
<a title="Unique_String" href="#">
<div style="" data-section="image" class="image_in_fixed_ratio_wrapper">
<div class="inner visible">
<img alt="Unique_String" src="image1.jpg" class="" style="" />
</div>
</div>
</a>
</div>
<div data-section="data">
<div class="product_description">
<div data-field="description_detail">
<h3><a title="Unique_String" href="#">Product Name<div class="donotwantthistoinclude">New</div></a></h3>
<a title="Unique_String" href="#"><p>Product Type / Product Power Unit</p></a>
<div data-field="price">
<a title="Unique_String" href="#">5,000</a>
</div>
<div data-field="description">
<a title="Unique_String" href="#">
<span>Height (mm)</span> 2344
|
<span>Other attribute 1</span> Duplex
|
<span>Other attribute 2 (kg)</span> 1400
|
<span>Other attribute 3</span> 2014
| <span>Other attribute X (h)</span> 772
<br /><span>Location</span> D - 85716
</a>
</div>
</div>
</div>
</div>
</div>
EOF;
$dom = new DomDocument();
$dom->loadXML($domDoc);
$xpath = new DomXPath($dom);
$products = [];
$productUniqueQuery = "//div[@data-field='description_detail']/h3/a/@title";
$productUniqueNodes = $xpath->query($productUniqueQuery);
if (!is_null($productUniqueNodes)) {
foreach ($productUniqueNodes as $productUniqueNode) {
$product = [];
$product["unique"] = $productUniqueNode->nodeValue;
$productNameQuery = sprintf("//h3/a[@title='%s']/text()",$product["unique"]);
$productNameNodes = $xpath->query($productNameQuery);
$product["name"] = $productNameNodes[0]->nodeValue;
$productImageQuery = sprintf("//img[@alt='%s']/@src",$product["unique"]);
$productImageNodes = $xpath->query($productImageQuery);
$product["imageURL"] = $productImageNodes[0]->nodeValue;
$productTypeQuery = sprintf("//a[@title='%s']/p/text()",$product["unique"]);
$productTypeNodes = $xpath->query($productTypeQuery);
list($product["type"], $product["powerUnit"]) = explode(" / ", $productTypeNodes[0]->nodeValue);
$productDescriptionQuery = sprintf("//div[@data-field='description']/a[@title='%s']/child::node()",$product["unique"]);
$productDescriptionNodes = $xpath->query($productDescriptionQuery);
$description = "";
foreach ($productDescriptionNodes as $productDescriptionNode) {
$nodeText = preg_replace("/\s*\|/","",trim($productDescriptionNode->nodeValue));
if($nodeText == "" || $productDescriptionNode->nodeType === 3){
continue;
}
$product[$nodeText] = preg_replace("/\s*\|/","",trim($productDescriptionNode->nextSibling->nodeValue));
}
$products[$product["unique"]] = $product;
}
}
try {
$db = new PDO("mysql:host=HOST;dbname=DBNAME;port=3306","USERNAME", "PASSWORD");
}
catch(PDOException $e){
echo "Connection failed: " . $e->getMessage();
exit();
}
$sql = 'INSERT INTO product_table (unique, name, type, power_unit, attr1) values (:unique, :name, :type, :power_unit, :attr1)';
$stmt = $db->prepare($sql);
foreach($products as $product){
$params = [
":unique"=>$product["unique"],
":name"=>$product["name"],
":type"=>$product["type"],
":power_unit"=>$product["powerUnit"],
":attr1"=>$product["Other attribute 1"]
];
var_dump($product);
$stmt->execute($params);
}
?>
</pre>
但是产品有很多属性,所以,我尝试获取这个产品属性,它位于1个html元素中,所以我需要将它拆分为一个数组,用于不同的属性:
$types = $xpath->query("//div[contains(concat(' ', normalize-space(@class), ' '), ' product_description ')]/div/a/p");
if (!is_null($types)) {
foreach ($types as $type) {
$nodes = $type->childNodes;
foreach ($nodes as $node) {
list($typee,$power_unit) = explode(' / ', $node->nodeValue);
$import_type = 'INSERT INTO product_table (id, type, power_unit) values ("", "' . strip_tags(trim($typee)) . '", "' . strip_tags(trim($power_unit)) . '")';
mysql_query($import_type);
}
}
}
简言之,我需要获得3个产品属性,当然,它们更多,我只想找出最好的解决方案,让它从外部网站工作,并将其插入我的数据库,如:
product_name_1 product_type_1 $power_unit_1
...
product_name_X product_type_X $power_unit_X
到目前为止,我试图将第二个xpath部分放在第一个foreach中,但它并没有按需要工作。。。
我是否应该尝试使用xpath节点创建数组,如$prodcuts=arrayfirstXpathNode、secondXpathNode等。。以这种方式工作,还是有更好更正确的解决方案
提前-TXN获取任何提示
编辑:
下面是我试图获取数据的示例HTML,这是针对产品的,每个产品都有用于显示数据的HTML:
<div class="single_product">
<div data-section="featured_image">
<a title="Unique_String" href="#">
<div style="" data-section="image" class="image_in_fixed_ratio_wrapper">
<div class="inner visible">
<img alt="Unique_String" src="image1.jpg" class="" style="">
</div>
</div>
</a>
</div>
<div data-section="data">
<div class="product_description">
<div data-field="description_detail">
<h3><a title="Unique_String" href="#">Product Name<div class="donotwantthistoinclude">New</div></a></h3>
<a title="Unique_String" href="#"><p>Product Type / Product Power Unit</p></a>
<div data-field="price">
<a title="Unique_String" href="#">5,000</a>
</div>
<div data-field="description">
<a title="Unique_String" href="#">
<span>Height (mm)</span> 2344
|
<span>Other attribute 1</span> Duplex
|
<span>Other attribute 2 (kg)</span> 1400
|
<span>Other attribute 3</span> 2014
| <span>Other attribute X (h)</span> 772
<br><span>Location</span> D - 85716
</a>
</div>
</div>
</div>
</div>
</div>
如果将第一个foreach中的产品名称分离为一个变量,则可以基于产品名称构建相对XPATH。我假设产品名称在页面上是唯一的。然后,第二个XPATH在页面上找到产品名称,并沿着元素向下走一点。现在,肯定会有更好的XPATH查询来实现这一点,我自己还没有达到这个技能水平,但我确实给了您一种方法 因此,流程将类似于: 对于每个产品,获取名称,在新查询中插入名称以获取特定产品的类型和电源单元,解析变量,插入数据库 警告 您正在使用危险且过时的SQL。请使用较新的mysqli_*或PDO库使用准备好的语句访问数据库。我没有更新你的代码来反映这一点,谷歌很容易做到 不过,我确实在您现有的SQL中插入了product_名称,以说明如何收集所有3个字段
$product_names = $xpath->query("//div[contains(concat(' ', normalize-space(@class), ' '), ' product_description ')]/div/h3/a");
if (!is_null($product_names)) {
foreach ($product_names as $product_name) {
$nodes = $product_name->childNodes;
foreach ($nodes as $node) {
$productName = preg_replace('~\\s+\\S+$~', "", strip_tags(trim($node->nodeValue)));
$xpath_relative = sprintf("//div[contains(concat(' ', normalize-space(@class), ' '), ' product_description ')]/div/h3/a[contains(text(),'%s')]/../../a/p",$productName);
$types = $xpath->query($xpath_relative);
if (!is_null($types)) {
foreach ($types as $type) {
$types_nodes = $type->childNodes;
foreach ($types_nodes as $type_node) {
list($typee,$power_unit) = explode(' \'', $type_node->nodeValue);
// WARNING!!! SQL INJECTION BELOW!!!
$import_type = 'INSERT INTO product_table (id, type, power_unit, product_name) values ("", "' . strip_tags(trim($typee)) . '", "' . strip_tags(trim($power_unit)) . '", "' . $product_name . '")';
mysql_query($import_type);
}
}
}
}
}
}
编辑2
我已经获取了您的代码并在PHP中运行,结果如下。我还根据提供的结构优化了XPATH查询,并提供了使用PDO的建议。只需根据需要填写更多属性。我将留给您完整的代码,包括我使用的DOM和XPATH初始化,以便您自己处理
如果将第一个foreach中的产品名称分离为一个变量,则可以基于产品名称构建相对XPATH。我假设产品名称在页面上是唯一的。然后,第二个XPATH在页面上找到产品名称,并沿着元素向下走一点。现在,肯定会有更好的XPATH查询来实现这一点,我自己还没有达到这个技能水平,但我确实给了您一种方法 因此,流程将类似于: 对于每个产品,获取名称,在新查询中插入名称以获取特定产品的类型和电源单元,解析变量,插入数据库 警告 您正在使用危险且过时的SQL。请使用较新的mysqli_*或PDO库使用准备好的语句访问数据库。我没有更新你的代码来反映这一点,谷歌很容易做到 不过,我确实在您现有的SQL中插入了product_名称,以说明如何收集所有3个字段
$product_names = $xpath->query("//div[contains(concat(' ', normalize-space(@class), ' '), ' product_description ')]/div/h3/a");
if (!is_null($product_names)) {
foreach ($product_names as $product_name) {
$nodes = $product_name->childNodes;
foreach ($nodes as $node) {
$productName = preg_replace('~\\s+\\S+$~', "", strip_tags(trim($node->nodeValue)));
$xpath_relative = sprintf("//div[contains(concat(' ', normalize-space(@class), ' '), ' product_description ')]/div/h3/a[contains(text(),'%s')]/../../a/p",$productName);
$types = $xpath->query($xpath_relative);
if (!is_null($types)) {
foreach ($types as $type) {
$types_nodes = $type->childNodes;
foreach ($types_nodes as $type_node) {
list($typee,$power_unit) = explode(' \'', $type_node->nodeValue);
// WARNING!!! SQL INJECTION BELOW!!!
$import_type = 'INSERT INTO product_table (id, type, power_unit, product_name) values ("", "' . strip_tags(trim($typee)) . '", "' . strip_tags(trim($power_unit)) . '", "' . $product_name . '")';
mysql_query($import_type);
}
}
}
}
}
}
编辑2
我已经获取了您的代码并在PHP中运行,结果如下。我还根据提供的结构优化了XPATH查询,并提供了使用PDO的建议。只需根据需要填写更多属性。我将留给您完整的代码,包括我使用的DOM和XPATH初始化,以便您自己处理
可以做的一件事是,在使用XPath时,可以使用一个节点作为进一步搜索的上下文,因此一旦有了产品节点列表,就可以将其用作提取其他数据的点 举个例子 请注意evaluate方法的第二个参数,即第一个查询中的节点 我还使用了evaluate,它允许我直接将节点作为字符串返回,而无需进一步转换。它允许我将字符串用作查询的一部分
没有后期处理,因此您可能需要整理一些数据,也没有数据库访问权限。您应该按照使用预处理语句的示例进行操作,但这说明了首先提取数据的重要部分。可以做的一件事是,在使用XPath时,您可以使用一个节点作为进一步搜索的上下文,因此,一旦有了产品节点列表,就可以将其用作提取其他数据的点 举个例子 请注意evalua的第二个参数 te方法,它是第一个查询中的节点 我还使用了evaluate,它允许我直接将节点作为字符串返回,而无需进一步转换。它允许我将字符串用作查询的一部分
没有后期处理,因此您可能需要整理一些数据,也没有数据库访问权限。您应该遵循使用预处理语句的示例,但这首先说明了提取数据的重要部分。如果您发布一些示例数据,可能会有所帮助。是的,我用包含产品信息的示例html编辑了我的线程!我下面的回答有什么不清楚的吗?不幸的是似乎不起作用。。。问题是产品名称不是唯一的,但发现有一个元素的标题是唯一的,其中包含括号中包含的唯一id。我编辑的源html要清楚!我想从这个html中得到的是:图像url的父元素a具有唯一的标题,产品名称的父元素a具有唯一的标题,产品类型/产品电源单元的父元素a具有唯一标题,且div数据字段中的所有属性=说明的父元素a具有唯一标题,每个属性位于单独的列中!我让它为这两个参数工作,我需要指导,但不知怎的,它插入了两次1产品。。。对于div data field=description元素和图像url中需要的其他属性,我需要使用foreach附加xpath?如果发布一些示例数据,可能会有所帮助。是的,我使用包含产品信息的示例html编辑了我的线程!我下面的回答有什么不清楚的吗?不幸的是似乎不起作用。。。问题是产品名称不是唯一的,但发现有一个元素的标题是唯一的,其中包含括号中包含的唯一id。我编辑的源html要清楚!我想从这个html中得到的是:图像url的父元素a具有唯一的标题,产品名称的父元素a具有唯一的标题,产品类型/产品电源单元的父元素a具有唯一标题,且div数据字段中的所有属性=说明的父元素a具有唯一标题,每个属性位于单独的列中!我让它为这两个参数工作,我需要指导,但不知怎的,它插入了两次1产品。。。对于div data field=description元素和图像url中需要的其他属性,我需要使用foreach附加xpath?啊,忘了计算。。。在我上面的回答中,这会让我的生活简单得多。。。Lol虽然此代码比提供Canis的代码短,但它不会循环遍历所有“单产品”元素,只返回第一个产品的信息……抱歉,我没有测试过。我已经更新了代码。我不应该使用//来开始检索XPath中的子数据,而应该使用后代::来确保它只在子XML实体中查找。它在查看两个记录,但总是找到第一个记录数据。啊,忘了评估。。。在我上面的回答中,这会让我的生活简单得多。。。Lol虽然此代码比提供Canis的代码短,但它不会循环遍历所有“单产品”元素,只返回第一个产品的信息……抱歉,我没有测试过。我已经更新了代码。我不应该使用//来开始检索XPath中的子数据,而应该使用后代::来确保它只在子XML实体中查找。它在查看两条记录,但总是找到第一条记录的数据。@Mole_LR太棒了!很高兴我能帮忙!我从html源代码中错误地理解了一件事——事实上,某些产品的图像alt可能不是“唯一”字符串,但某些产品的图像alt可能不同!因此,我们如何解决获取图像src的问题,因为$productImageQuery=sprintf//img[@alt='%s']/@src,$product[sku];在现实中不起作用。我们可以使用父元素标题…好的,解决了:$productImageQuery=sprintf//a[@title='%s']/div/div/img/@src,$product[sku]@Mole_LR啊,你能赶上真是太好了,这是一个很好的调整。@Mole_LR请记住接受并投票给正确的答案,投票给有用的答案和评论。@Mole_LR太好了!很高兴我能帮忙!我从html源代码中错误地理解了一件事——事实上,某些产品的图像alt可能不是“唯一”字符串,但某些产品的图像alt可能不同!因此,我们如何解决获取图像src的问题,因为$productImageQuery=sprintf//img[@alt='%s']/@src,$product[sku];在现实中不起作用。我们可以使用父元素标题…好的,解决了:$productImageQuery=sprintf//a[@title='%s']/div/div/img/@src,$product[sku]@Mole_LR啊,你能赶上真是太好了,这是一个很好的调整。@Mole_LR请记住接受并向上投票正确的答案,向上投票有用的答案和评论。