anvisa-bot 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/FLUXO_SITE_ANVISA.txt +38 -0
- data/README.textile +64 -0
- data/Rakefile +53 -0
- data/bin/anvisa-bot +35 -0
- data/lib/anvisa_bot.rb +31 -0
- data/lib/anvisa_browser.rb +101 -0
- data/lib/anvisa_parser.rb +90 -0
- metadata +89 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
===Fluxo para pesquisa por num. de registro no site da Anvisa===
|
2
|
+
|
3
|
+
POST rconsulta_produto_internet.asp
|
4
|
+
|
5
|
+
CO_TIPO_PRODUTO=8
|
6
|
+
Area=Cosmético
|
7
|
+
Processo=
|
8
|
+
Produto=
|
9
|
+
Registro=
|
10
|
+
CNPJ=
|
11
|
+
NO_EMPRESA=
|
12
|
+
|
13
|
+
-recebo o html de produtos.
|
14
|
+
-extrair os links e executar:
|
15
|
+
|
16
|
+
POST rconsulta_produto_detalhe.asp
|
17
|
+
|
18
|
+
CO_PRODUTO=var_codigo
|
19
|
+
NO_EMPRESA=var_empresa
|
20
|
+
NU_CNPJ=var_cnpj
|
21
|
+
REGISTRO=var_registro
|
22
|
+
|
23
|
+
NU_PROCESSO=
|
24
|
+
NO_PRODUTO=
|
25
|
+
NU_REGISTRO=
|
26
|
+
NU_AUTORIZACAO=
|
27
|
+
|
28
|
+
CO_TIPO_PRODUTO=8
|
29
|
+
hdnpgAtual=1
|
30
|
+
hdnmodo=
|
31
|
+
PROCESSO=
|
32
|
+
PRODUTO=
|
33
|
+
EMPRESA=
|
34
|
+
CNPJ=
|
35
|
+
|
36
|
+
-recebe o html de detalhe do produto
|
37
|
+
-extrair as informacoes e retornar
|
38
|
+
|
data/README.textile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
h1. anvisa-bot
|
2
|
+
|
3
|
+
anvisa-bot é uma API Ruby para consultar Produtos para Saúde Registrados.
|
4
|
+
|
5
|
+
Até o momento, somente a busca por registro anvisa foi implementada.
|
6
|
+
Esta API faz requests e parse no HTML do site da anvisa para fornecer informações sobre produtos.
|
7
|
+
|
8
|
+
Site da Anvisa:
|
9
|
+
|
10
|
+
http://www.anvisa.gov.br/scriptsweb/correlato/correlato.htm
|
11
|
+
|
12
|
+
h2. Instalação
|
13
|
+
|
14
|
+
@sudo gem install rogerleite-anvisa-bot -s http://gems.github.com@
|
15
|
+
|
16
|
+
h2. Usando como executável
|
17
|
+
|
18
|
+
$ anvisa-bot "numero_registro_anvisa" <br>
|
19
|
+
Por exemplo:
|
20
|
+
@anvisa-bot 10008530225@
|
21
|
+
|
22
|
+
h2. Usando a API Ruby
|
23
|
+
|
24
|
+
<pre>
|
25
|
+
require "rubygems"
|
26
|
+
require "anvisa_bot"
|
27
|
+
|
28
|
+
produto = AnvisaBot.consulta_produto_por_registro(10247530027)
|
29
|
+
|
30
|
+
puts produto.empresa
|
31
|
+
puts produto.cnpj
|
32
|
+
puts produto.autorizacao
|
33
|
+
puts produto.nome
|
34
|
+
puts produto.modelo
|
35
|
+
puts produto.registro
|
36
|
+
puts produto.processo
|
37
|
+
puts produto.origem
|
38
|
+
puts produto.vencimento_registro
|
39
|
+
</pre>
|
40
|
+
|
41
|
+
h2. LICENSE:
|
42
|
+
|
43
|
+
(The MIT License)
|
44
|
+
|
45
|
+
Copyright (c) 2008 FIX
|
46
|
+
|
47
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
48
|
+
a copy of this software and associated documentation files (the
|
49
|
+
'Software'), to deal in the Software without restriction, including
|
50
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
51
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
52
|
+
permit persons to whom the Software is furnished to do so, subject to
|
53
|
+
the following conditions:
|
54
|
+
|
55
|
+
The above copyright notice and this permission notice shall be
|
56
|
+
included in all copies or substantial portions of the Software.
|
57
|
+
|
58
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
59
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
60
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
61
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
62
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
63
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
64
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/specification'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
GEM = "anvisa-bot"
|
8
|
+
GEM_VERSION = "0.2.3"
|
9
|
+
SUMMARY = "Pesquisa de produtos para saúde registrados"
|
10
|
+
AUTHOR = "Roger Leite"
|
11
|
+
EMAIL = "roger.barreto@gmail.com"
|
12
|
+
HOMEPAGE = "http://github.com/rogerleite/anvisa-bot"
|
13
|
+
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.name = GEM
|
17
|
+
s.version = GEM_VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.summary = SUMMARY
|
20
|
+
s.require_paths = ['bin', 'lib']
|
21
|
+
s.files = FileList['bin/*.rb', 'lib/**/*.rb', '[A-Z]*'].to_a
|
22
|
+
s.executables = ["anvisa-bot"]
|
23
|
+
|
24
|
+
s.author = AUTHOR
|
25
|
+
s.email = EMAIL
|
26
|
+
s.homepage = HOMEPAGE
|
27
|
+
|
28
|
+
s.rubyforge_project = GEM # GitHub bug, gem isn't being build when this miss
|
29
|
+
|
30
|
+
s.add_dependency(%q<hpricot>, [">= 0.8.1"])
|
31
|
+
end
|
32
|
+
|
33
|
+
Spec::Rake::SpecTask.new do |t|
|
34
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
35
|
+
t.spec_opts = %w(-fs --color)
|
36
|
+
end
|
37
|
+
|
38
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
39
|
+
pkg.gem_spec = spec
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Install the gem locally"
|
43
|
+
task :install => [:package] do
|
44
|
+
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "Create a gemspec file"
|
48
|
+
task :make_spec do
|
49
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
50
|
+
file.puts spec.to_ruby
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
data/bin/anvisa-bot
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Exemplo de comando:
|
4
|
+
# ruby bin/anvisa-bot.rb 10008530225
|
5
|
+
# exemplos de registros anvisa:
|
6
|
+
# - 10008530225
|
7
|
+
# - 10247530027
|
8
|
+
# - 80175510005
|
9
|
+
|
10
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../lib")
|
11
|
+
|
12
|
+
require "anvisa_bot"
|
13
|
+
|
14
|
+
args = ARGV.dup
|
15
|
+
ARGV.clear
|
16
|
+
|
17
|
+
puts "usage: anvisa-bot <registro_anvisa>"
|
18
|
+
|
19
|
+
numero_registro = args[0]
|
20
|
+
produto = AnvisaBot.consulta_produto_por_registro(numero_registro)
|
21
|
+
|
22
|
+
puts produto.to_yaml
|
23
|
+
|
24
|
+
=begin
|
25
|
+
puts <<HTML
|
26
|
+
<html>
|
27
|
+
<body>
|
28
|
+
<div>
|
29
|
+
<p>empresa: #{produto.empresa}</p><br>
|
30
|
+
<p>modelo: #{produto.modelo}</p>
|
31
|
+
</div>
|
32
|
+
</body>
|
33
|
+
</html>
|
34
|
+
HTML
|
35
|
+
=end
|
data/lib/anvisa_bot.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "anvisa_browser"
|
2
|
+
require "anvisa_parser"
|
3
|
+
|
4
|
+
class AnvisaBot
|
5
|
+
|
6
|
+
#veja o fluxo de "navegacao" do bot no arquivo fluxo_site_anvisa.txt
|
7
|
+
def self.consulta_produto_por_registro(numero_registro)
|
8
|
+
begin
|
9
|
+
anvisa_browser = create_anvisa_browser
|
10
|
+
plain_html = anvisa_browser.consulta_produto_por_registro(numero_registro)
|
11
|
+
|
12
|
+
#puts "ZZZ ... ~10 segs"
|
13
|
+
#sleep( rand(10) ) #para não chamar atencao do server
|
14
|
+
|
15
|
+
links = AnvisaParser.find_links_produtos(plain_html)
|
16
|
+
return Produto.new({:not_found => true}) if links.empty?
|
17
|
+
|
18
|
+
plain_html = anvisa_browser.consulta_produto_detalhe(numero_registro, links.first)
|
19
|
+
AnvisaParser.extract_produto(plain_html)
|
20
|
+
rescue => ex
|
21
|
+
Produto.new({:error => ex})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#usado para injetar stubs ao rodar specs
|
26
|
+
def self.create_anvisa_browser
|
27
|
+
AnvisaBrowser.new
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
class AnvisaBrowser
|
5
|
+
|
6
|
+
ANVISA_URL = 'http://www7.anvisa.gov.br/datavisa/Consulta_Produto_correlato/'
|
7
|
+
USER_AGENT = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.13) Gecko/2009080315 Ubuntu/9.04 (jaunty) Firefox/3.0.13"
|
8
|
+
DEBUG_REQ = false
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :default_headers
|
12
|
+
end
|
13
|
+
self.default_headers = {
|
14
|
+
'User-Agent' => USER_AGENT,
|
15
|
+
'Accept' => 'text/html',
|
16
|
+
'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7'
|
17
|
+
}
|
18
|
+
|
19
|
+
def consulta_produto_por_registro(numero_registro)
|
20
|
+
plain_url = "#{ANVISA_URL}rconsulta_produto_internet.asp"
|
21
|
+
params = {
|
22
|
+
:CO_TIPO_PRODUTO => '8', :Area => 'Cosmético', :Processo => '',
|
23
|
+
:Produto => '', :CNPJ => '', :NO_EMPRESA => '',
|
24
|
+
:Registro => numero_registro
|
25
|
+
}
|
26
|
+
|
27
|
+
user_headers = {
|
28
|
+
'Referer' => 'http://www7.anvisa.gov.br/datavisa/Consulta_Produto_correlato/consulta_correlato.asp'
|
29
|
+
}
|
30
|
+
|
31
|
+
simple_post(plain_url, params, user_headers)
|
32
|
+
end
|
33
|
+
|
34
|
+
def consulta_produto_detalhe(numero_registro, link_produto)
|
35
|
+
plain_url = "#{ANVISA_URL}rconsulta_produto_detalhe.asp"
|
36
|
+
params = {
|
37
|
+
:CO_PRODUTO => link_produto.codigo,
|
38
|
+
:NO_EMPRESA => link_produto.empresa,
|
39
|
+
:NU_CNPJ => link_produto.cnpj,
|
40
|
+
:REGISTRO => numero_registro,
|
41
|
+
:NU_PROCESSO => '',
|
42
|
+
:NO_PRODUTO => '',
|
43
|
+
:NU_REGISTRO => '',
|
44
|
+
:NU_AUTORIZACAO => '',
|
45
|
+
:CO_TIPO_PRODUTO => '8',
|
46
|
+
:hdnpgAtual => '1',
|
47
|
+
:hdnmodo => '',
|
48
|
+
:PROCESSO => '',
|
49
|
+
:PRODUTO => '',
|
50
|
+
:EMPRESA => '',
|
51
|
+
:CNPJ => ''
|
52
|
+
}
|
53
|
+
|
54
|
+
user_headers = {
|
55
|
+
'Referer' => 'http://www7.anvisa.gov.br/datavisa/Consulta_Produto_correlato/consulta_correlato.asp'
|
56
|
+
}
|
57
|
+
|
58
|
+
simple_post(plain_url, params, user_headers)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
# Faz um post simples e retorna o "plain html" da pagina.
|
63
|
+
# fonte: http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTP.html
|
64
|
+
def simple_post(plain_url, params, user_headers)
|
65
|
+
url = URI.parse(plain_url)
|
66
|
+
|
67
|
+
headers = self.class.default_headers.merge(user_headers)
|
68
|
+
|
69
|
+
req = Net::HTTP::Post.new(url.path, headers)
|
70
|
+
req.set_form_data(params)
|
71
|
+
|
72
|
+
if DEBUG_REQ
|
73
|
+
puts "=== Debug Http Request"
|
74
|
+
puts "url => #{url}"
|
75
|
+
puts "body => #{req.body}"
|
76
|
+
puts "=== Fim Debug Http Request"
|
77
|
+
end
|
78
|
+
|
79
|
+
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
|
80
|
+
case res
|
81
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
82
|
+
# OK
|
83
|
+
else
|
84
|
+
res.error!
|
85
|
+
end
|
86
|
+
|
87
|
+
plain_html = res.body
|
88
|
+
if DEBUG_REQ
|
89
|
+
puts "=== Debug Http Response Body"
|
90
|
+
puts plain_html
|
91
|
+
puts "=== Fim Debug Http Response Body"
|
92
|
+
end
|
93
|
+
plain_html
|
94
|
+
end
|
95
|
+
|
96
|
+
def make_headers(user_headers)
|
97
|
+
self.class.default_headers.merge(user_headers)
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "hpricot"
|
3
|
+
|
4
|
+
class AnvisaParser
|
5
|
+
|
6
|
+
DEBUG = false
|
7
|
+
|
8
|
+
def self.find_links_produtos(plain_html)
|
9
|
+
html = Hpricot(plain_html)
|
10
|
+
links = []
|
11
|
+
html.search('a[@href*="ver_detalhes"]').each do |link|
|
12
|
+
#link['href'] returns:
|
13
|
+
#javascript:ver_detalhes('302629','LABORAT%C3%93RIOS%20B.%20BRAUN%20S/A','31673254000102');
|
14
|
+
params = link['href'].scan(/'([^']*)'/) #ER, pega os valores que estão dentro das ''
|
15
|
+
links << LinkProduto.new(params[0].to_s, params[1].to_s, params[2].to_s)
|
16
|
+
end
|
17
|
+
links
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.extract_produto(plain_html)
|
21
|
+
|
22
|
+
html = Hpricot(plain_html)
|
23
|
+
|
24
|
+
table = html.at("table.formulario")
|
25
|
+
#devido a html errado da anvisa (ln 106 e 116), subo dois niveis e ignoro o primeiro td
|
26
|
+
table = table.parent.parent.parent
|
27
|
+
|
28
|
+
values = []
|
29
|
+
ignore_first = true
|
30
|
+
table.search("td").each do |td|
|
31
|
+
if ignore_first
|
32
|
+
ignore_first = false
|
33
|
+
next
|
34
|
+
end
|
35
|
+
if DEBUG
|
36
|
+
puts '=== td.inner_html ==='
|
37
|
+
puts td.inner_html
|
38
|
+
end
|
39
|
+
value = td.inner_html
|
40
|
+
value.gsub!(/ /, ' ') #substitui o espaco do html por espaco
|
41
|
+
value.strip! #remove espacos adicionais
|
42
|
+
value.gsub!(/(<br>|<br\s\/>)/, "\n")
|
43
|
+
value.gsub!(/<[^>]*>/, '') #remove qualquer tag restante
|
44
|
+
values << value
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
Produto.new(:empresa => values[0], :cnpj => values[1], :autorizacao => values[2],
|
49
|
+
:nome => values[3], :modelo => values[4], :registro => values[5],
|
50
|
+
:processo => values[6], :origem => values[7], :vencimento_registro => values[8])
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
class LinkProduto
|
56
|
+
|
57
|
+
attr_accessor :codigo, :empresa, :cnpj
|
58
|
+
|
59
|
+
def initialize(codigo, empresa, cnpj)
|
60
|
+
@codigo = codigo
|
61
|
+
@empresa = empresa
|
62
|
+
@cnpj = cnpj
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
class Produto
|
68
|
+
|
69
|
+
attr_accessor :empresa, :cnpj, :autorizacao,
|
70
|
+
:nome, :modelo, :registro,
|
71
|
+
:processo,:origem, :vencimento_registro,
|
72
|
+
:error, :not_found
|
73
|
+
|
74
|
+
def initialize(args)
|
75
|
+
raise ArgumentError("Args have to be a Hash with attributes") unless args.is_a?(Hash)
|
76
|
+
args.each do |att, value|
|
77
|
+
self.send("#{att}=", value)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def error?
|
82
|
+
!!error
|
83
|
+
end
|
84
|
+
|
85
|
+
def not_found?
|
86
|
+
!!not_found
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: anvisa-bot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 17
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 3
|
10
|
+
version: 0.2.3
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Roger Leite
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-06-16 00:00:00 -03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: hpricot
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 61
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 8
|
33
|
+
- 1
|
34
|
+
version: 0.8.1
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
description:
|
38
|
+
email: roger.barreto@gmail.com
|
39
|
+
executables:
|
40
|
+
- anvisa-bot
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- lib/anvisa_bot.rb
|
47
|
+
- lib/anvisa_parser.rb
|
48
|
+
- lib/anvisa_browser.rb
|
49
|
+
- Rakefile
|
50
|
+
- FLUXO_SITE_ANVISA.txt
|
51
|
+
- README.textile
|
52
|
+
- bin/anvisa-bot
|
53
|
+
has_rdoc: true
|
54
|
+
homepage: http://github.com/rogerleite/anvisa-bot
|
55
|
+
licenses: []
|
56
|
+
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
|
60
|
+
require_paths:
|
61
|
+
- bin
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 3
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
version: "0"
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project: anvisa-bot
|
84
|
+
rubygems_version: 1.4.1
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: "Pesquisa de produtos para sa\xC3\xBAde registrados"
|
88
|
+
test_files: []
|
89
|
+
|