Случайно отсутствующие узлы в html при очистке с помощью GuzzleClient - PullRequest
0 голосов
/ 11 мая 2018

Я имею дело с проблемой скрепа из-за несогласованности дочерних элементов, которые иногда присутствуют, а другие отсутствуют.

Поскольку я сохраняю состояние, ссылаясь на массив $values[],я обнаружил, что иногда $value[18] - это адрес электронной почты, в других случаях это может быть телефон или факс.

Примерный массив из трех итераций выглядит следующим образом:

[0] => [
    [1] => Firm: The Firm One Name
    [2] => Firm:
    [3] => The Firm One Name
    [4] => Office: 5th Av. 18980, NY
    [5] => Office:
    [6] => 5th Av. 18980, NY
    [7] => City: New York 
    [8] => City:
    [9] => New York
    [10] => Country: USA
    [11] => Country:
    [12] => USA
    [13] => Tel: +123 4 567 890
    [14] => Tel:
    [15] => +123 4 567 890
    [16] => Email: person.one@example.com
    [17] => Email:
    [18] => person.one@example.com
],
[1] => [
    [1] => Firm: The Firm Two Name
    [2] => Firm:
    [3] => The Firm Two Name
    [4] => Office: 5th Av. 342680, NY
    [5] => Office:
    [6] => 5th Av. 342680, NY
    [7] => City: New York
    [8] => City:
    [9] => New York
    [10] => Country: USA
    [11] => Country:
    [12] => USA
    [13] => Tel: +123 4 567 890
    [14] => Tel:
    [15] => +123 4 567 890
    [16] => Fax: +123 4 567 891
    [17] => Fax:
    [18] => +123 4 567 891
    [19] => Email: person.two@example.com
    [20] => Email:
    [21] => person.two@example.com
],
    [2] => [[1] => Firm: The Firm Three Name
    [2] => Firm:
    [3] => The Firm Three Name
    [4] => Office: 5th Av. 89280, NY
    [5] => Office:
    [6] => 5th Av. 89280, NY
    [7] => Country: USA
    [8] => Country:
    [9] => USA
    [10] => Fax: +123 4 567 899
    [11] => Fax:
    [12] => +123 4 567 899
    [13] => Email: person.three@example.com
    [14] => Email:
    [15] => person.three@example.com
]

Какэто может быть заметно, когда я повторяю и сохраняю $values[15] из последнего массива, который является адресом электронной почты, на первом [0][15] соответствует тел.номер.

У меня вопрос: есть ли более простой способ, чем делать «сумасшедший цикл» над полями и всегда сохранять электронную почту как электронную почту, а не как номер телефона?

Я использую GuzzleClient() вместе с $node->filterXPath() и / или $node->filter() в зависимости от того, что мне нужно захватить.

Структура HTML, над которой я работаю, очень короткая и простая, какВ приведенном ниже примере иногда отсутствуют узлы ... :

<div id="profiledtails">
<div class="abc-g">
    <div class="abc-gf">
        <div class="abc-u first">Firm:</div>
        <div class="abc-u">
            <a href="http://example.com/123456/" title="More information here" class="Item" abc-tracker="office" abc-tracking="true">Person One</a>
        </div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Office:</div>
        <div class="abc-u">
            <address>
                5th Av.<br>18980,<br>NY
            </address>
        </div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">City:</div>
        <div class="abc-u">New York</div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Country:</div>
        <div class="abc-u">USA</div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Tel:</div>
        <div class="abc-u">+123 4 567 890</div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Fax:</div>
        <div class="abc-u">+123 4 567 891</div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Email:</div>
        <div class="abc-u">
            <a href="mailto:mperson.one@example.com">person.one@example.com</a></div>
    </div>
</div>

Ответы [ 3 ]

0 голосов
/ 11 мая 2018

Это можно легко сделать с помощью регулярного выражения, я не очень разбираюсь в PHP, но для регулярного выражения:

Вы можете использовать следующую команду для ключа:

class="abc-u first">(.*):

& для значения:

class="abc-u">(.*?)</ 
0 голосов
/ 11 мая 2018

После некоторого отдыха и свежего обдумывания проблемы я нашел решение, которое обеспечивает необходимую дезинфекцию данных.В конце концов, это всего лишь вопрос фильтрации результатов и получения правильных значений в правильном месте в массиве.Вот что я делаю и работаю для любого случая (когда адаптирован к нуждам):

$crawler->filterXPath('//*[@id="profiledetails"]/div')->each(function($node) use ($data, $start, $i) {

    // get the values
    foreach($node->filter('div') as $k => $v) {
        $values[] = trim($v->nodeValue);
    }

    // sanitise the data
    $sanitised = [];
    foreach($values as $k => $v) {
        trim($v); // trim to make sure there's no spaces
        if($v == 'Firm:') {
            $sanitised['firm_name'] = $values[$k + 1]; // Note: the +1 is to get the next node where the value is set
        }
        if($v == 'Office:') {
            $sanitised['address'] = $values[$k + 1];
        }
        if($v == 'City:') {
            $sanitised['city'] = $values[$k + 1];
        }
        if($v == 'Country:') {
            $sanitised['country'] = $values[$k + 1];
        }
        if($v == 'Tel:') {
            $sanitised['phone'] = $values[$k + 1];
        }
        if($v == 'Fax:') {
            $sanitised['fax'] = $values[$k + 1];
        }
        if($v == 'Email:') {
            $sanitised['email'] = $values[$k + 1];
        }
    }

    $data['firm_name'] = !empty($sanitized['firm_name']) ? $sanitized['firm_name'] : null;
    $data['address'] = !empty($sanitized['address']) ? nl2br($sanitized['address']) : null;
    $data['city'] = !empty($sanitized['city']) ? $sanitized['city'] : null;
    $data['country'] = !empty($sanitized['country']) ? $sanitized['country'] : null;
    $data['phone'] = !empty($sanitized['phone']) ? $sanitized['phone'] : null;
    $data['fax'] = !empty($sanitized['fax']) ? $sanitized['fax'] : null;
    $data['email'] = !empty($sanitized['email']) ? $sanitized['email'] : null;

    // Save the data    
    ProfileModel::where('id', $i)->update($data);
    // just a console log to know where we are in case it fails on timeout
    echo "Done for profile id " . $i . PHP_EOL;    
});

Результатом всегда будет для каждой итерации правильный массив, даже если найдены пустые или отсутствующие узлы.Это выглядит так:

[ 
    ['firm_name'] = 'Firm Name One';
    ['address'] = '5th Av.<br>18980,<br>NY';
    ['city'] = 'New Yok';
    ['country'] = 'USA';
    ['phone'] = '+123 4 567 890';
    ['fax'] = null;
    ['email'] = 'person.one@example.com';
]

И теперь каждая строка в БД получает данные (или NULL) в правильных столбцах.

0 голосов
/ 11 мая 2018

Я имел дело с той же ситуацией и раньше, и единственное решение для этой ситуации - Регулярное выражение , потому что элементы HTML меняются каждый раз, и вы не можете отслеживать значения, пока не используете регулярное выражение. Вот вашfix

$re = '/        <div class="abc-u first">Email:<\/div>
        <div class="abc-u">
            <a href="mailto:mperson.one@example.com">(.*)<\/a>/';
$str = '<div id="profiledtails">
<div class="abc-g">
    <div class="abc-gf">
        <div class="abc-u first">Firm:</div>
        <div class="abc-u">
            <a href="http://example.com/123456/" title="More information here" class="Item" abc-tracker="office" abc-tracking="true">Person One</a>
        </div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Office:</div>
        <div class="abc-u">
            <address>
                5th Av.<br>18980,<br>NY
            </address>
        </div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">City:</div>
        <div class="abc-u">New York</div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Country:</div>
        <div class="abc-u">USA</div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Tel:</div>
        <div class="abc-u">+123 4 567 890</div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Fax:</div>
        <div class="abc-u">+123 4 567 891</div>
    </div>
    <div class="abc-gf">
        <div class="abc-u first">Email:</div>
        <div class="abc-u">
            <a href="mailto:mperson.one@example.com">person.one@example.com</a></div>
    </div>
</div>';

preg_match($re, $str, $matches, PREG_OFFSET_CAPTURE, 0);

// Print the entire match result
var_dump($matches);

Таким же образом, вы должны подготовить регулярное выражение для других значений, и вы готовы к работе, приведенный выше код выглядит грязно, но вы можете удалить пробелы из строки, а также из регулярного выражения, чтобы сделать его чистым.

...