Библиотека Ruby Mechanize web scraper возвращает файл вместо страницы - PullRequest
1 голос
/ 03 августа 2011

Я недавно использовал камень механизации в ruby, чтобы написать скребок. К сожалению, URL, который я пытаюсь очистить, возвращает объект Mechanize::File вместо объекта Mechanize::Page при запросе GET.

Я не могу понять, почему. Каждый другой URL, который я пробовал, возвращал объект Mechanize::Page.

Есть ли способ заставить Mechanize вернуть Page объект?

Ответы [ 3 ]

4 голосов
/ 10 апреля 2012

Вот что происходит.

Когда вы загружаете «обычную» веб-страницу, ее заголовок будет иметь поле, похожее на Content-Type text/html. Когда Mechanize видит это, он знает, как интерпретировать содержимое страницы как HTML, и анализирует его в объект Mechanize :: Page, содержащий ссылки, формы и тому подобное.

Но если вы когда-либо нажимали на ссылку с надписью «загрузить данные CSV» или «скачать PDF» или, в общем, все, что не является HTML, вы получаете страницу, на которой нет Content-Type text/html. Поскольку Mechanize не может проанализировать не-html в объект Mechanize :: Page, он упакует содержимое в объект Mechanize :: File.

То, что вы делаете с объектом Mechanize :: File, зависит от того, что вы пытаетесь выполнить. Например, если вы знаете, что страница, которую вы посетили, представляла собой данные CSV, а не HTML, вы можете извлечь данные CSV следующим образом:

page = web_agent.get(some_url_that_references_csv_data)
parsed_csv = CSV.parse(page.body)

Если вы хотите проявить фантазию, вы можете написать свои собственные парсеры, которые позволят Mechanize обрабатывать не-HTML форматы. Смотрите Механизировать документы на PluggableParser , если вы хотите пойти по этому пути. Но вы можете многого добиться, работая напрямую с объектом Mechanize :: File.

дополнение в ответ на комментарий @ user741072

Если, с другой стороны, если страница имеет значение HTML и кто-то пренебрегал указанием content-type на HTML, вы можете написать метод, который заменяет html-анализатор на анализатор по умолчанию достаточно долго, чтобы разобрать страницу. Это заставит анализировать как HTML:

def with_html_parser(agent, &body)
  original_parser = agent.pluggable_parser.default
  agent.pluggable_parser.default = agent.pluggable_parser['text/html']
  begin
    yield
  ensure
    agent.pluggable_parser.default = original_parser
  end
end

Дайте мне знать, если это поможет.

3 голосов
/ 20 сентября 2011

Если веб-сайт не возвращает тип контента в качестве части ответа, вы можете самостоятельно установить тип контента в хуке пост-соединения:

agent = Mechanize.new { |a|
  a.post_connect_hooks << lambda { |_,_,response,_|
    if response.content_type.nil? || response.content_type.empty?
      response.content_type = 'text/html'
    end
  }
}
0 голосов
/ 05 августа 2011

обратите внимание на Content-Type определенного URL в HTTP-заголовках с помощью curl (curl yoururl -i). В вашем коде вы можете проверить тип содержимого, прежде чем получите URL:

require 'net/http'
url = URI.parse('http://www.gesetze-im-internet.de/bundesrecht/bgb/gesamt.pdf')
res = Net::HTTP.start(url.host, url.port) {|http| http.head(url.path)}
puts res['content-type']

#=> application/pdf

Или вы можете просто проверить, принадлежит ли ваш объект Mechanize классу Mechanize::Page:

agent = Mechanize.new
unknown_body = agent.get(url)
if unknown_body.class == Mechanize::Page
  self.body = unknown_body
else
  puts "Discarded binary content!"
end

Имейте в виду, что этот подход будет намного медленнее, поскольку он в любом случае «загружает» запрошенный ресурс. Но это может быть полезно, если вы хотите сохранить файл для дальнейшего использования.

...