2017-02-09 37 views
0

Я использую Watir для очистки результатов поиска с веб-сайта и ввода их в файл CSV. Когда я запускаю поиск, результаты делятся на классы span. Таким образом, HTML будет выглядеть примерно так:Когда веб-соскабливание с Ватиром, как мне разобрать результаты в том же классе и ввести их в отдельные ячейки CSV?

<span class="sn_auth_name">foo</span> 
<span class="sn_target_lang">English</span> 

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

sn_auth_name = row.xpath('span[@class="sn_auth_name"]/text()').text.strip 
sn_target_lang = row.xpath('span[@class="sn_target_lang"]/text()').text.strip 

CSV.open("file.csv", "a") do |csv| 
     csv << [sn_auth_name, sn_target_lang] 

Вопрос заключается в том, что для некоторых из результатов поиска, есть несколько элементов, присвоенные к одному классу. То есть, иногда есть только один sn_auth_name, а иногда их три! Прямо сейчас оба результата попадают в одну ячейку в моем CSV-файле.

Есть ли способ, с помощью которого я могу обрабатывать время от времени, получая более одного результата, присвоенного одному классу? Решение, в котором второй (или третий) результат вводится в отдельную ячейку?

Спасибо!

Кто-то запросил более подробную информацию, так что вот выход, который я обычно получаю.

<table class="restable"><tr> 
<td class="res1">1/1</td> 
<td class="res2"> 
    <span class="sn_auth_name">Imām</span>, 
    <span class="sn_auth_firstname">Abū Bakr</span>: 
    <span class="sn_target_title">Al-Kalām rasmāl</span> [ 
    <span class="sn_target_lang">Arabic</span>]/ 
    <span class="sn_transl_name">Ḥijāzī al-Sayyid</span>, 
    <span class="sn_transl_firstname">Muṣṭafā</span>/
    <span class="sn_pub"> 
     <span class="place">Al-Qāhirah</span>: 
     <span class="publisher">Al-Majlis al-Alā lil-Thaqāfah</span> [ 
     <span class="sn_country">Egypt</span>]</span>, 
    <span class="sn_year">2000</span>. 
    <span class="sn_pagination">588 p.</span> 
    <span class="sn_orig_title">Magana jarice</span> [ 
    <span class="sn_orig_lang">Afrikaans</span>] 
</td></tr> 
</table> 

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

<tr> 
<td class="res1">7/8</td> 
<td class="res2"> 
    <span class="sn_auth_name">Plenge</span>, 
    <span class="sn_auth_firstname">Vagn</span>; 
    <span class="sn_auth_name">Wyk</span>, 
    <span class="sn_auth_firstname">Chris van</span>: 
    <span class="sn_target_title">Opbrud</span> [ 
    <span class="sn_target_lang">Danish</span>]/
    <span class="sn_transl_name">Hansen</span>, 
    <span class="sn_transl_firstname">Finn Holten</span>; 
    <span class="sn_transl_name">Madelung</span>, 
    <span class="sn_transl_firstname">Marianne</span>; 
    <span class="sn_transl_name">Seiketso</span>, 
    <span class="sn_transl_firstname">Helen Gaohenngwe</span>/
    <span class="sn_pub"> 
     <span class="place">Frederiksberg</span>: 
     <span class="publisher">AKS</span>, 
     <span class="place">Frederiksberg</span>: 
     <span class="publisher">Hjulet</span> [ 
     <span class="sn_country">Denmark</span>]</span>, 
    <span class="sn_year">2000</span>. 
    <span class="sn_pagination">247 p.</span> [ 
    <span class="sn_orig_lang">Afrikaans</span>], [ 
    <span class="sn_orig_lang">English</span>] 
</td></tr> 

Вот, например, есть несколько записей для sn_auth_name. И то, что заканчивается в моем CSV-файле, - это ячейка с PlengeWyk. Идеальным было бы создать скрипт для создания значения sn_auth_name2 и записать его в отдельной ячейке, то есть Plenge и Wyk.

Любые мысли?

+1

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

+0

То есть, Джастин. Я добавил несколько примеров вывода. – NCG

+0

В вашем примере кода, что такое 'row'? Элементы Watir не имеют метода 'xpath'.Вы используете Nokogiri для анализа HTML? –

ответ

0

Метод #xpath возвращает NodeSet, который представляет собой набор совпадающих узлов. NodeSet включает Enumerable, который предоставляет ряд методов для итерации по коллекции. Вместо того, чтобы получать текст всего набора узлов, вы хотите перебирать каждый узел и собирать его текст.

sn_auth_name = row.xpath('span[@class="sn_auth_name"]').map { |node| node.text.strip } 
#=> ["Plenge", "Wyk"] 

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

csv << [*sn_auth_name, sn_target_lang] 

Если несколько выравниваться, вы можете также сгладить весь массив:

csv << [sn_auth_name, sn_target_lang].flatten 

Doing выше будет означать, что каждая строка имеет разное количество столбцов. Вы можете заполнить все строки так, чтобы они имели одинаковое количество столбцов:

# Variable to define which column is the first name column 
col_auth_name = 0 

# Collect the data from the table into an Array 
data = [] 
doc.css('td.res2').each do |row| 
    sn_auth_name = row.xpath('span[@class="sn_auth_name"]').map { |node| node.text.strip } 
    sn_target_lang = row.xpath('span[@class="sn_target_lang"]/text()').text.strip 
    data << [sn_auth_name, sn_target_lang] 
end 

# Determine max number of names in a row 
max_auth_name = data.map { |row| row[col_auth_name].length }.max 

CSV.open("file.csv", "a") do |csv| 
    data.each do |row| 
    # Fill the Array of names to meet the max length 
    row[col_auth_name].fill('', row[col_auth_name].length..(max_auth_name - 1)) 

    # Write to the CSV file 
    csv << row.flatten 
    end 
end 
+0

Это работает как шарм. Спасибо! – NCG

+0

Последующий вопрос. Поскольку NodeSets не содержат одинаковое количество узлов последовательно, когда я сглаживаю массив и помещаю его в CSV, я не могу сохранить количество столбцов согласованным по строкам. Например, если у меня есть запись с одним именем 'sn_auth_name', а следующая запись имеет два, второе' sn_auth_name' заканчивается в столбце для 'sn_auth_firstname'. Есть ли способ избежать этого? – NCG

+0

Это будет действительно зависеть от того, что вы хотите сохранить в файле CSV. Вы можете сохранить все имена в одной ячейке, но разделите ее так, чтобы ее можно было прочитать - например, ячейка имела бы «Plenge, Wyk». Если вам действительно нужны отдельные столбцы, вам придется произвольно решить, сколько столбцов должно быть, а затем проложить каждую строку, чтобы иметь это число. –