2017-02-09 11 views
0

저는 Watir을 사용하여 웹 사이트에서 검색 결과를 긁어내어 CSV 파일에 입력합니다. 검색을 실행하면 결과가 스팬 클래스로 나뉩니다. 그래서 HTML은 같은 모양 :Watir을 사용하여 웹을 긁을 때 동일한 클래스에서 결과를 파싱하고 별도의 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 값을 만들고이를 별도의 셀 (예 : PlengeWyk)에 기록하도록하는 것입니다.

의견이 있으십니까?

+1

행이 가질 수있는 다른 레이아웃과 각각에 대해 예상되는 결과를 제공하면 도움이됩니다. –

+0

저스틴입니다. 출력 예제를 추가했습니다. – NCG

+0

코드 예제에서 정확히'row'는 무엇입니까? Watir 요소에는'xpath' 메소드가 없습니다.Nokogiri를 사용하여 HTML을 구문 분석합니까? –

답변

0

#xpath 메서드는 일치하는 노드의 컬렉션 인 NodeSet을 반환합니다. NodeSet에는 Enumerable이 포함되어 있습니다. Enumerable은 컬렉션을 반복하는 여러 가지 메서드를 제공합니다. 전체 노드 집합의 텍스트를 가져 오는 대신 각 노드를 반복하고 텍스트를 수집해야합니다. 이름의 배열로

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

sn_auth_name은 여전히 ​​하나의 셀에 CSV에 기록 얻을 것이다. 각 이름을 자체 셀에 쓰려면 Array를 병합해야합니다. 각 행은을 가지고 있음을 의미합니다 위의 수행

csv << [sn_auth_name, sn_target_lang].flatten 

: 패턴 화 된 여러가있는 경우

csv << [*sn_auth_name, sn_target_lang] 

, 당신은 또한 전체 배열을 평평하게 할 수 있습니다 : 당신이 중 하나 플랫를 사용하여 개별 열을 평평하게 할 수 있습니다 다른 수의 열. 모든 행을 채워서 같은 수의 열을 채울 수 있습니다.

# 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'을 가진 엔트리를 가지고 있고, 다음 엔트리가 2라면, 두 번째'sn_auth_name'은'sn_auth_firstname'에 대한 열로 끝납니다. 이 일이 발생하지 않도록하는 방법이 있습니까? – NCG

+0

정말 CSV 파일을 원하는대로 달라집니다. 하나의 셀에 모든 이름을 유지할 수 있지만 읽을 수 있도록 구분합니다 (예 : 셀에 "Plenge, Wyk"가 있음). 실제로 별도의 열을 원할 경우 열 수를 임의로 결정한 다음 각 행을 그 수만큼 채워야합니다. –