[Piracicaba/SP] 2 vagas para Analista Programador Python Jr https://t.co/L5rBFjtDl7
Facebook
Python Brasil
[Piracicaba/SP] 2 vagas para Analista Programador Python Jr
We are proude to announce our next confirmed keynote is Alisson Kaptur (@akaptur). Happy to have you here in... https://t.co/TnVYWCXTTZ
Facebook
Python Brasil
We are proude to announce our next confirmed keynote is Alisson Kaptur (@akaptur). Happy to have you here in "beagá" on #pybr #uaipython Not yet registered? http://2017.pythonbrasil.org.br/#tickets
RT @akaptur: Excited to report I'll be keynoting @pythonbrasil in October! https://t.co/mLur5wjwHS #pybr13
2017.pythonbrasil.org.br
PythonBrasil 13 />
<meta name=
<meta name=
13ª Conferência Brasileira da Comunidade Python. São seis dias de atividades! Palestras de 6 a 8 de Outubro. Tutoriais e sprints de 9 a 11 de Outubro.
50° Encontro do Grupo de Usuários Python de Pernambuco!!!!! 👏👏👏 #pugpe #python https://t.co/jHSUatr0qr
Facebook
Python Brasil
50° Encontro do Grupo de Usuários Python de Pernambuco!!!!! 👏👏👏 #pugpe #python
Django project optimization guide (part 1)
http://dizballanze.com/django-project-optimization-part-1/
http://dizballanze.com/django-project-optimization-part-1/
Ô sô, ainda não se inscreveu neste trem? Tem só mais um tiquim de dias para adquirir o lote 1. Se inscreve uai!!!... https://t.co/79OSaqSRbO
Facebook
Python Brasil
Ô sô, ainda não se inscreveu neste trem? Tem só mais um tiquim de dias para adquirir o lote 1. Se inscreve uai!!! http://2017.pythonbrasil.org.br/
Ô sô, ainda não se inscreveu neste trem? Tem só mais um tiquim de dias o lote 1. #uaipython #pybr13… https://t.co/7G87npc8Og
Twitter
Python Brasil
Ô sô, ainda não se inscreveu neste trem? Tem só mais um tiquim de dias o lote 1. #uaipython #pybr13 https://t.co/I1MyUKnS6c Vem uai!
RT @taniaandrea_com: In memoriam @jeanferri. Thank you my friend... https://t.co/3m59akpOgB #muitoobrigada #amigos #python #pythonbrasil…
Associação Python Brasil
In memoriam (Jean Ferri)
Quem ainda não comprou passagem para a #pybr13, neste fim de semana Latam esta com promoção, Ida e volta saindo… https://t.co/wAbwNVoyw7
Twitter
Python Brasil
Quem ainda não comprou passagem para a #pybr13, neste fim de semana Latam esta com promoção, Ida e volta saindo de São Paulo, por 215. https://t.co/7WRIQfvTbY
Não podia faltar ela...nossa querida pylady Paola Katherine( @pk_pacheco) também será keynote na #pybr13... https://t.co/zmoHOzrahH
Facebook
Python Brasil
Não podia faltar ela...nossa querida pylady Paola Katherine( @pk_pacheco) também será keynote na #pybr13 #uaipython!! 😍 Eleita recentemente para a diretoria da PSF, ela é orgulho para toda nossa...
RT @pythonbrasil: Não podia faltar ela...nossa querida pylady Paola Katherine( @pk_pacheco) também será keynote na #pybr13... https://t.co/…
Primeiro lote acabando em 3...2...1. Corre que ainda dá tempo de aproveitar o primeiro lote! #uaipython #pybr13… https://t.co/NKs87fJMe3
Twitter
Python Brasil
Primeiro lote acabando em 3...2...1. Corre que ainda dá tempo de aproveitar o primeiro lote! #uaipython #pybr13 https://t.co/Kq2WDRCMVL https://t.co/1zJLIKpi9x
RT @FilipeCifali: 8 dias galera!! Garanta já seu ingresso para a #PythonSul 2017 @catarse https://t.co/ltfAoj68F4 via @catarse
Catarse
pythonsul2017
Um evento organizado pela comunidade e para a comunidade!
Forwarded from A P
Olá, pessoal!
A Myreks está aberta para quem quiser conhecer e fazer parte do time.
Estamos com a posição para Operations Engineer aberta, para ajudar a construir nossa cultura devops, colaboração entre as pessoas e evolução contínua do produto.
A descrição da vaga está aqui:
https://www.myreks.com/v3/vagas....
Quem quiser conversar, pode me procurar direto, andre@myreks.com, skype:andre.pastore, telegram:apast, twitter:apast, ou pode escrever nos canais do site.
A Myreks está aberta para quem quiser conhecer e fazer parte do time.
Estamos com a posição para Operations Engineer aberta, para ajudar a construir nossa cultura devops, colaboração entre as pessoas e evolução contínua do produto.
A descrição da vaga está aqui:
https://www.myreks.com/v3/vagas....
Quem quiser conversar, pode me procurar direto, andre@myreks.com, skype:andre.pastore, telegram:apast, twitter:apast, ou pode escrever nos canais do site.
Criando um bot de notícias para o Telegram usando Scrapy e Firebase
http://feedproxy.google.com/~r/NullOnError/~3/tphk9yKZ8bE/
Problema
Eu costumo pegar com frequência a rodovia Régis Bittencourt (http://www.autopistaregis.com.br/) e o que acontece com frequência é o trânsito parar completamente no meio do nada e sem acesso à internet, então eu fico sem a mínima noção do que está acontecendo e em quanto tempo conseguirei chegar ao meu destino.
Pensando nisso, decidi escrever um pequeno bot para o Telegram que publica num canal as notícias da estrada! Como de costume no NULL on error, vou explicar como fiz.
Web scraping
http://feedproxy.google.com/~r/NullOnError/~3/tphk9yKZ8bE/
Problema
Eu costumo pegar com frequência a rodovia Régis Bittencourt (http://www.autopistaregis.com.br/) e o que acontece com frequência é o trânsito parar completamente no meio do nada e sem acesso à internet, então eu fico sem a mínima noção do que está acontecendo e em quanto tempo conseguirei chegar ao meu destino.
Pensando nisso, decidi escrever um pequeno bot para o Telegram que publica num canal as notícias da estrada! Como de costume no NULL on error, vou explicar como fiz.
Web scraping
O primeiro passo é extrair as informações do site. Eu optei por utilizar o framework Scrapy (https://scrapy.org/), por alguns motivos que ficarão bem claros abaixo e por ter bastante experiência escrevendo web crawlers com o Scrapy, eu não pretendo escrever um tutorial a respeito neste artigo, isso ficará para uma próxima oportunidade.
Antes de tudo eu preciso definir o que eu quero extrair; isso é feito definindo uma class com N campos (https://doc.scrapy.org/en/latest/topics/items.html#scrapy.item.Field) herdando de scrapy.Item (https://doc.scrapy.org/en/latest/topics/items.html)
class Entry(Item):
uid = Field()
spider = Field()
timestamp = Field()
content = Field()
Como é possível notar a aranha, ou crawler ficou bem simples, mas como pode ser visto abaixo, vou explicar cada parte a seguir.
class RegisSpider(CrawlSpider):
name = 'regis'
allowed_domains = ['autopistaregis.com.br']
start_urls = ['http://www.autopistaregis.com.br/?link=noticias.todas']
rules = (
Rule(LinkExtractor(allow=r'\?link=noticias.?ver*'), callback='parse_news'),
)
def parse_news(self, response):
loader = EntryLoader(item=Entry(), response=response)
loader.add_xpath('content', '//*[@id="noticia"]/p[not(position() > last() -3)]//text()')
return loader.load_item()
A propriedade start_urls indica onde a aranha vai iniciar a varredura de páginas
Após isso, definimos algumas regras. Vou usar um LinkExtractor (https://doc.scrapy.org/en/latest/topics/link-extractors.html), que, como o próprio nome diz é um componente para extrair links seguindo uma regra das páginas encontradas. Nesse caso eu usei uma expressão regular que bate com todas as URLS de notícias do site, e defino um callback que será chamado para cada página chamado parse_news
LinkExtractor(allow=r'\?link=noticias.?ver*'), callback='parse_news')
Então é aqui que a mágica toda acontece: passei algum tempo analisando o código fonte da página e usando o inspetor web para poder gerar um xpath que bata com notícia, excluindo as informações extras na página.
XPath
O XPath (https://www.w3schools.com/xml/xml_xpath.asp) é uma forma de atravessar o html e extrair alguma informação específica. É uma linguagem bem poderosa, neste caso eu usei a expressão [not(position() > last() -3)] para excluir os últimos 3 parágrafos marcados pela tag , que o site sempre coloca como uma forma de rodapé. Infelizmente, nem sempre os sites seguem boas práticas, o que me facilitaria e muito a extração dos dados!
loader.add_xpath('content', '//*[@id="noticia"]/p[not(position() > last() -3)]//text()')
Os outros campos, como ID da noticía e timestamp são “extraídos” usando um middleware chamado scrapy-magicfields (https://github.com/scrapy-plugins/scrapy-magicfields), desta maneira:
MAGIC_FIELDS = {
'uid': "$response:url,r'id=(\d+)'",
'spider': '$spider:name',
'timestamp': "$time",
}
O próximo passo é rodar o web crawler periodicamente. Eu usei o sistema de cloud do scrapinghub, que é a empresa que desenvolve o Scrapy e outras ferramentas de scraping, nele eu posso configurar para rodar de tempos em tempos o crawler. No meu caso eu configurei para rodar a cada 30 minutos,
Mesmo que possível, eu não posso publicar diretamente, apenas as novas notícias, caso contrário toda vez que o crawler rodar eu estaria poluindo o canal com as notícias repetidas. Então eu decidi salvar num banco de dados intermediário para conseguir distinguir o que é novo do que já foi indexado.
Persistência
Eis que entra o Firebase (https://firebase.google.com/), e sua nova funcionalidade chamada de functions (https://firebase.google.com/docs/functions), com o qual, eu posso escrever uma função que reage a determinados eventos no banco de dados, como por exemplo, quando um novo dado é inserido.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const request = require('request-promise');
Antes de tudo eu preciso definir o que eu quero extrair; isso é feito definindo uma class com N campos (https://doc.scrapy.org/en/latest/topics/items.html#scrapy.item.Field) herdando de scrapy.Item (https://doc.scrapy.org/en/latest/topics/items.html)
class Entry(Item):
uid = Field()
spider = Field()
timestamp = Field()
content = Field()
Como é possível notar a aranha, ou crawler ficou bem simples, mas como pode ser visto abaixo, vou explicar cada parte a seguir.
class RegisSpider(CrawlSpider):
name = 'regis'
allowed_domains = ['autopistaregis.com.br']
start_urls = ['http://www.autopistaregis.com.br/?link=noticias.todas']
rules = (
Rule(LinkExtractor(allow=r'\?link=noticias.?ver*'), callback='parse_news'),
)
def parse_news(self, response):
loader = EntryLoader(item=Entry(), response=response)
loader.add_xpath('content', '//*[@id="noticia"]/p[not(position() > last() -3)]//text()')
return loader.load_item()
A propriedade start_urls indica onde a aranha vai iniciar a varredura de páginas
Após isso, definimos algumas regras. Vou usar um LinkExtractor (https://doc.scrapy.org/en/latest/topics/link-extractors.html), que, como o próprio nome diz é um componente para extrair links seguindo uma regra das páginas encontradas. Nesse caso eu usei uma expressão regular que bate com todas as URLS de notícias do site, e defino um callback que será chamado para cada página chamado parse_news
LinkExtractor(allow=r'\?link=noticias.?ver*'), callback='parse_news')
Então é aqui que a mágica toda acontece: passei algum tempo analisando o código fonte da página e usando o inspetor web para poder gerar um xpath que bata com notícia, excluindo as informações extras na página.
XPath
O XPath (https://www.w3schools.com/xml/xml_xpath.asp) é uma forma de atravessar o html e extrair alguma informação específica. É uma linguagem bem poderosa, neste caso eu usei a expressão [not(position() > last() -3)] para excluir os últimos 3 parágrafos marcados pela tag , que o site sempre coloca como uma forma de rodapé. Infelizmente, nem sempre os sites seguem boas práticas, o que me facilitaria e muito a extração dos dados!
loader.add_xpath('content', '//*[@id="noticia"]/p[not(position() > last() -3)]//text()')
Os outros campos, como ID da noticía e timestamp são “extraídos” usando um middleware chamado scrapy-magicfields (https://github.com/scrapy-plugins/scrapy-magicfields), desta maneira:
MAGIC_FIELDS = {
'uid': "$response:url,r'id=(\d+)'",
'spider': '$spider:name',
'timestamp': "$time",
}
O próximo passo é rodar o web crawler periodicamente. Eu usei o sistema de cloud do scrapinghub, que é a empresa que desenvolve o Scrapy e outras ferramentas de scraping, nele eu posso configurar para rodar de tempos em tempos o crawler. No meu caso eu configurei para rodar a cada 30 minutos,
Mesmo que possível, eu não posso publicar diretamente, apenas as novas notícias, caso contrário toda vez que o crawler rodar eu estaria poluindo o canal com as notícias repetidas. Então eu decidi salvar num banco de dados intermediário para conseguir distinguir o que é novo do que já foi indexado.
Persistência
Eis que entra o Firebase (https://firebase.google.com/), e sua nova funcionalidade chamada de functions (https://firebase.google.com/docs/functions), com o qual, eu posso escrever uma função que reage a determinados eventos no banco de dados, como por exemplo, quando um novo dado é inserido.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const request = require('request-promise');
const buildUrl = require('build-url');
admin.initializeApp(functions.config().firebase);
exports.notifyChannel = functions.database.ref('/news/{what}/{uid}')
.onCreate(event => {
const config = functions.config().telegram;
const url = buildUrl('https://api.telegram.org', {
path: `bot${config.bot.token}/sendMessage`,
queryParams: {
chat_id: config.channel.chat_id,
}
});
return request({
method: 'POST',
uri: url,
resolveWithFullResponse: true,
body: {
text: event.data.val().content
},
json: true
}).then(response => {
if (response.statusCode === 200) {
return response.body.id;
}
throw response.body;
}
);
});
Essa função é bem simples; basicamente, em qualquer evento de onCreate ela é chamada, eu faço uma chamada POST na API do Telegram com o nome do canal, token do bot e conteúdo, que no caso é o texto da notícia.
admin.initializeApp(functions.config().firebase);
exports.notifyChannel = functions.database.ref('/news/{what}/{uid}')
.onCreate(event => {
const config = functions.config().telegram;
const url = buildUrl('https://api.telegram.org', {
path: `bot${config.bot.token}/sendMessage`,
queryParams: {
chat_id: config.channel.chat_id,
}
});
return request({
method: 'POST',
uri: url,
resolveWithFullResponse: true,
body: {
text: event.data.val().content
},
json: true
}).then(response => {
if (response.statusCode === 200) {
return response.body.id;
}
throw response.body;
}
);
});
Essa função é bem simples; basicamente, em qualquer evento de onCreate ela é chamada, eu faço uma chamada POST na API do Telegram com o nome do canal, token do bot e conteúdo, que no caso é o texto da notícia.