2016-06-13 6 views
0

저는 Sidekiq와 Mechanize를 사용하여 간단한 웹 스파이더를 구축하고 있습니다.Sidekiq는 덮어 쓰기 인스턴스를 기계화합니다.

하나의 도메인에서이를 실행할 때 제대로 작동합니다. 여러 도메인에서 실행하면 실패합니다. 그 이유는 다른 Sidekiq 직원이 web_page을 인스턴스화 할 때 덮어 씌워진다는 것이 그 이유라고 믿습니다. 그러나 사실인지 또는 어떻게 해결할 지 확신 할 수 없습니다.

# my scrape_search controller's create action searches on google. 
def create 
    @scrape = ScrapeSearch.build(keywords: params[:keywords], profession: params[:profession]) 
    agent = Mechanize.new 
    scrape_search = agent.get('http://google.com/') do |page| 
    search_result = page.form... 
    search_result.css("h3.r").map do |link| 
     result = link.at_css('a')['href'] # Narrowing down to real search results 
     @domain = Domain.new(some params) 
     ScrapeDomainWorker.perform_async(@domain.url, @domain.id, remaining_keywords) 
    end 
    end 
end 

도메인 당 사이드킥 작업을 만들고 있습니다. 내가 찾는 도메인의 대부분은 몇 페이지 만 포함해야하므로 페이지 당 하위 작업이 필요하지 않습니다. 내가 단일 도메인을 긁어 때

class ScrapeDomainWorker 
    include Sidekiq::Worker 
    ... 

    def perform(domain_url, domain_id, keywords) 
    @domain  = Domain.find(domain_id) 
    @domain_link = @domain.protocol + '://' + domain_url 
    @keywords  = keywords 

    # First we scrape the homepage and get the first links 
    @domain.to_parse = ['/'] # to_parse is an array of PATHS to parse for the domain 
    mechanize_path('/') 
    @domain.verified << '/' # verified is an Array field containing valid domain paths 
    get_paths(@web_page) # Now we should have to_scrape populated with homepage links 

    @domain.scraped = 1 # Loop counter 
    while @domain.scraped < 100 
     @domain.to_parse.each do |path| 
     @domain.to_parse.delete(path) 
     @domain.scraped += 1 
     mechanize_path(path) # We create a Nokogiri HTML doc with mechanize for the valid path 
     ... 
     get_paths(@web_page) # Fire this to repopulate to_scrape !!! 
     end 
    end 
    @domain.save 
    end 

    def mechanize_path(path) 
    agent = Mechanize.new 
    begin 
     @web_page = agent.get(@domain_link + path) 
    rescue Exception => e 
     puts "Mechanize Exception for #{path} :: #{e.message}" 
    end 
    end 

    def get_paths(web_page) 
    paths = web_page.links.map {|link| link.href.gsub((@domain.protocol + '://' + @domain.url), "") } ## This works when I scrape a single domain, but fails with ".gsub for nil" when I scrape a few domains. 
    paths.uniq.each do |path| 
     @domain.to_parse << path 
    end 
    end 

end 

이 작동하지만 몇 도메인을 긁어 때 web_page에 대한 .gsub for nil와 함께 실패

내 노동자입니다.

당신은 다른 클래스에서 당신의 코드를 포장하고 만들고 노동자 내에서 그 클래스의 객체 수
+0

스택 오버플로에 오신 것을 환영합니다. "[mcve]"를 읽으십시오. 문제를 재현하는 코드를 최소한으로 줄이십시오. –

답변

0

:

class ScrapeDomainWrapper 
    def initialize(domain_url, domain_id, keywords) 
    # ... 
    end 

    def mechanize_path(path) 
    # ... 
    end 

    def get_paths(web_page) 
    # ... 
    end 
end 

그리고 당신의 직원 : 마음에

또한
class ScrapeDomainWorker 
    include Sidekiq::Worker 

    def perform(domain_url, domain_id, keywords) 
    ScrapeDomainWrapper.new(domain_url, domain_id, keywords) 
    end 
end 

, 곰 Mechanize::Page#links을 그 nil 일 수 있습니다.

+0

내가 제안한대로 포장했습니다. 또한 모든 인스턴스 변수를 로컬 변수로 변환했습니다 (@web_page는 web_page가되었습니다). 나는 여전히 "정의되지 않은 메소드'gsub 'for nil을 얻는다. NilClass for paths = web_page.links.map {| link | link.href.gsub ((@ domain.protocol + ': //'+ @ domain.url), ""}}. 이상하게도, 솔로로 돌리면 잘 작동합니다. – Ben

+0

코드를 다른 클래스로 옮긴 경우 변수의 이름을 바꿀 필요가 없습니다. 클래스 변수가 아니라 인스턴스 변수 인 경우 모든 사항이 정상입니다. 또한 어떤 경우에는'Mechanize :: Link # href'가'nil '이 될 수도 있습니다. 그걸 확인해야합니다. – Wikiti

+0

그래, 나는 그것을위한 failsafe를 추가했다. 도와 주셔서 감사합니다! – Ben