2013-11-26 1 views
1

Scrapy를 사용하여 웹 크롤러를 작성하여 특정 웹 페이지에서 토크백 텍스트를 다운로드합니다.Scrapy가 XPath 내용을 찾을 수 없습니다.

titles = hxs.xpath("//div[@class='site_comment site_comment-even large high-rank']") 

나중에 : 다음 메시지를 얻기 위해 XPath를 쓰는 동안

<div id="site_comment_71339" class="site_comment site_comment-even large high-rank"> 
    <div class="talkback-topic"> 
     <a class="show-comment" data-ajax-url="/comments/71339.js?counter=97&num=57" href="/comments/71339?counter=97&num=57">57. talk back title here </a> 
</div> 
    <div class="talkback-message"> blah blah blah talk-back message here </div> 
....etc etc etc ...... 

: 여기

는 특정 음성 안내 지원을위한 웹 페이지 뒤에있는 코드의 관련 부분이다

item["title"] = titles.xpath("div[@class='talkback-message']text()").extract() 

버그는 없지만 작동하지 않습니다. 어떤 아이디어? 나는 경로를 정확하게 쓰지 않을 것이라고 생각하지만, 오류를 발견 할 수 없다.

감사합니다 :)

전체 코드 : 여기

from scrapy.spider import BaseSpider 
from scrapy.selector import Selector 
from craigslist_sample.items import CraigslistSampleItem 

class MySpider(BaseSpider): 
    name = "craig" 
    allowed_domains = ["tbk.co.il"] 
    start_urls = ["http://www.tbk.co.il/tag/%D7%91%D7%A0%D7%99%D7%9E%D7%99%D7%9F_%D7%A0%D7%AA%D7%A0%D7%99%D7%94%D7%95/talkbacks"] 

    def parse(self, response): 
     hxs = Selector(response) 
     titles = hxs.xpath("//div[@class='site_comment site_comment-even large high-rank']") 
     items=[] 
     for titles in titles: 
      item = CraigslistSampleItem() 
      item["title"] = titles.xpath("div[@class='talkback-message']text()").extract() 
      items.append(item) 
     return items 
+1

글쎄, 확실히'text()'요소 앞에''div [@ class = 'talkback-message']/text()''라는 슬래시가 없습니다. 그래도이 모든 것이 될지 모르겠다. –

+0

@MarcusRickert에 감사하지만 문제는 "titles"변수에서 미리 시작됩니다 ("scrapy shell"을 사용하여 코드를 디버깅하고 빈 문자열을 반환 함). 그러나 코멘트 주셔서 감사합니다, 당신 말이 맞아요 (나는 당신을 믿는다는 것을 의미합니다. 나는 XPath를 작성하는 방법을 알지 못합니다 ...)). – Cheshie

+0

위에서 언급 한 URL에는 내용이 site_comment site_comment 인 클래스 속성이 없습니다 (심지어 상위 등급이 ""). 다시 확인해 주시겠습니까? 원시 HTML 소스를 보여 주거나'wget' 도구를 사용하여 브라우저를 검색하려면 브라우저의 기능을 사용하십시오. –

답변

5

는 "토크백 메시지"div가 아닌 #site_comment_74240

<div class="site_comment site_comment-even small normal-rank" id="site_comment_74240"> 
    <div class="talkback-topic"> 
     <a href="/comments/74240?counter=1&amp;num=144" class="show-comment" data-ajax-url="/comments/74240.js?counter=1&amp;num=144">144. מדיניות</a> 
    </div> 

    <div class="talkback-username"> 
     <table><tr> 
      <td>קייזרמן פרדי&nbsp;</td> 
      <td>(01.11.2013)</td> 
     </tr></table> 
    </div> 

의 HTML 페이지의 미리보기입니다 HTML 페이지를 처음 가져 오면 오히려 주석 제목을 클릭 할 때 일부 AJAX 쿼리를 통해 비동기 적으로 가져 오므로 각 주석에 대해 가져와야합니다. 문자열로 시작하는 "ID"속성을 가지고, 즉, 모든 div의 ""site_comment_ "당신은 또한 사용할 수 있습니다

//div[starts-with(@id, "site_comment_"]) :

코멘트 블록, 당신 코드 snipper에 titles,이 같은 XPath를 사용 잡고 할 수 있습니다 . (내가 XPath를 사용하여 위했던대로) Selector.css()와 CSS 선택기 귀하의 경우에, 당신은 그래서 중 하나를 사용하여 "ID"접근 방식을 주석 블록을 잡을 수 있습니다

titles = sel.css("div[id^=site_comment_]") 

또는없이 "site_comment"클래스를 사용하여 다른 "site_comment-even", "site_comment-odd", "small", "normal-ran"

titles = sel.css("div.site_comment") 

그런 다음 당신이 그 의견 div 내부 ./div[@class="talkback-topic"]/a[@class="show-comment"]/@data-ajax-url에서의 URL을 사용하여 새 Request을 발행 할 것입니다 : 다양 K "또는"높은 순위 ". 또는 CSS 선택자를 사용하여 div.talkback-topic > a.show-comment::attr(data-ajax-url) (단, ::attr(...)은 표준이 아니지만 의사 요소 기능을 사용하는 CSS 선택기의 Scrapy 확장 기능)

AJAX 호출에서 얻은 결과는 일부 자바 스크립트 코드이므로 old.after(...)

var old = $("#site_comment_72765"); 
old.attr('id', old.attr('id') + '_small'); 
old.hide(); 
old.after("\n<div class=\"site_comment site_comment-odd large high-rank\" id=\"site_comment_72765\">\n <div class=\"talkback-topic\">\n  <a href=\"/comments/72765?counter=42&amp;num=109\" class=\"show-comment\" data-ajax-url=\"/comments/72765.js?counter=42&amp;num=109\">109. ביבי - האדם הנכון בראש ממשלת ישראל(לת)<\/a>\n <\/div>\n \n  <div class=\"talkback-message\">\n   \n  <\/div>\n \n <div class=\"talkback-username\">\n  <table><tr>\n   <td>ישראל&nbsp;<\/td>\n   <td>(11.03.2012)<\/td>\n  <\/tr><\/table>\n <\/div>\n <div class=\"rank-controllers\">\n  <table><tr>\n   \n   <td class=\"rabk-link\"><a href=\"#\" data-thumb=\"/comments/72765/thumb?type=up\"><img alt=\"\" src=\"/images/elements/thumbU.png?1376839523\" /><\/a><\/td>\n   <td> | <\/td>\n   <td class=\"rabk-link\"><a href=\"#\" data-thumb=\"/comments/72765/thumb?type=down\"><img alt=\"\" src=\"/images/elements/thumbD.png?1376839523\" /><\/a><\/td>\n   \n    <td> | <\/td>\n    <td>11<\/td>\n   \n  <\/tr><\/table>\n <\/div>\n \n  <div class=\"talkback-links\">\n   <a href=\"/comments/new?add_to_root=true&amp;html_id=site_comment_72765&amp;sibling_id=72765\">תגובה חדשה<\/a>\n   &nbsp;&nbsp;\n   <a href=\"/comments/72765/comments/new?html_id=site_comment_72765\">הגיבו לתגובה<\/a>\n   &nbsp;&nbsp;\n   <a href=\"/i/offensive?comment_id=72765\" data-noajax=\"true\">דיווח תוכן פוגעני<\/a>\n  <\/div>\n \n<\/div>"); 
var new_comment = $("#site_comment_72765"); 

내부의 내용이 당신이 살전로 가야 당신이 해골 거미 뭔가 Selector(text=this_ajax_html_data)하고 .//div[@class="talkback-message"]//text()의 XPath 또는 div.talkback-message ::text CSS 셀렉터 여기

있어 사용하여 다시 분석해야합니다 HTML 데이터입니다 잡아 아이디어 :

from scrapy.spider import BaseSpider 
from scrapy.selector import Selector 
from scrapy.http import Request 
from craigslist_sample.items import CraigslistSampleItem 
import urlparse 
import re 


class MySpider(BaseSpider): 
    name = "craig" 
    allowed_domains = ["tbk.co.il"] 
    start_urls = ["http://www.tbk.co.il/tag/%D7%91%D7%A0%D7%99%D7%9E%D7%99%D7%9F_%D7%A0%D7%AA%D7%A0%D7%99%D7%94%D7%95/talkbacks"] 

    def parse(self, response): 
     sel = Selector(response) 
     comments = sel.css("div.site_comment") 
     for comment in comments: 
      item = CraigslistSampleItem() 
      # this probably has to be fixed 
      #item["title"] = comment.xpath("div[@class='talkback-message']text()").extract() 

      # issue an additional request to fetch the Javascript 
      # data containing the comment text 
      # and pass the incomplete item via meta dict 
      for url in comment.css('div.talkback-topic > a.show-comment::attr(data-ajax-url)').extract(): 
       yield Request(url=urlparse.urljoin(response.url, url), 
        callback=self.parse_javascript_comment, 
        meta={"item": item}) 
       break 

    # the line we are looking for begins with "old.after" 
    # and we want everythin inside the parentheses 
    _re_comment_html = re.compile(r'^old\.after\((?P<html>.+)\);$') 
    def parse_javascript_comment(self, response): 
     item = response.meta["item"] 
     # loop on Javascript content lines 
     for line in response.body.split("\n"): 
      matching = self._re_comment_html.search(line.strip()) 
      if matching: 
       # what's inside the parentheses is a Javascript strings 
       # with escaped double-quotes 
       # a simple way to decode that into a Python string 
       # is to use eval() 
       # then there are these "<\/tag>" we want to remove 
       html = eval(matching.group("html")).replace(r"<\/", "</") 

       # once we have the HTML snippet, decode it using Selector() 
       decoded = Selector(text=html, type="html") 

       # and save the message text in the item 
       item["message"] = u''.join(decoded.css('div.talkback-message ::text').extract()).strip() 
       # and return it 
       return item 

scrapy runspider tbkspider.py을 사용해보세요.

관련 문제