Python: RSS to Twitter (oauth версия)

11 марта 2012
Комментарии к записи Python: RSS to Twitter (oauth версия) отключены

Старый вариант репостинга в твиттер из RSS давно не работает.

Снова понадобилась такая штука, сделал новый вариант репостинга через oauth.

Используются модули oauth-python-twitter2 и python-bitly.

Все предельно просто, настройка заключается в заполнении значений переменных


bit_api=""
bit_login=""
consumer_key=""
consumer_secret=""
access_key=""
access_secret=""
rss_url="/rss"

После чего запуск скрипта в cron в соотвествии с требованиями по скорости постинга. Можно в принципе и в CMS встроить, чтобы постинг мгновенный был.

Сам код:


#!/usr/local/bin/python
# -*- coding: utf8 -*-
import urllib, libxml2, pickle, os
from time import sleep
from oauthtwitter import OAuthApi
import bitly
bit_api=""
bit_login=""
consumer_key=""
consumer_secret=""
access_key=""
access_secret=""
rss_url="/rss"
if __name__ == '__main__':
    doc = libxml2.parseFile(rss_url)
    links=[]
    for item in doc.xpathEval('//channel/item/link'):
        links.append(item.content)
    titles=[]
    for item in doc.xpathEval('//channel/item/title'):
        titles.append(item.content)
    rss_path = os.path.join(os.path.dirname(__file__), 'rss.db')
    file = open (rss_path)
    old_links=pickle.load(file)
    file.close()
    items=[]
    f= 0
    for x in xrange( 0,len(links)):
        for old in old_links:
            f= 0
            if (old==links[x]):
                f=1
                break
        if (f== 0):
            items.append(x)
    twitter = OAuthApi(consumer_key, consumer_secret, access_key, access_secret)
    bitly_api = bitly.Api(bit_login, bit_api)
    for x in items:
        title=titles[x].decode("utf8")
        if len(title)<=120:
            print "link %s: %s" % (x,links[x])
            if x!= 0:
                sleep(15)
            try:
                twitter.UpdateStatus(title+" "+bitly_api.shorten(links[x]))
                #print title.encode("utf8")+" "+bitly_api.shorten(links[x])
            except ValueError:
                pass
    file=open(rss_path,"w")
    ser=pickle.dump(links,file)
    file.close()

Критика, как обычно, приветствуется.

Опубликовал:

Решение задачки для php программистов с хабра

5 апреля 2011
Комментарии к записи Решение задачки для php программистов с хабра отключены

Увидел на хабре задачку при собеседовании для php программистов http://habrahabr.ru/blogs/php/116686/

Решил попробовать сам ее решить, вроде не сложно. вместе с отладкой, сделал за ~20минут, т.е. в норматив не уложился, что херово.

Получилось вот так,  хз насколько это оптимально. Есть идеи что улучшить?

<?php
function read_conf($path)
{
    $f=file_get_contents($path);
    //разбиваем на строки
    $lines=explode("\n",$f);
    $tmp=array();
 
    //режем строки на key=>value
    foreach($lines as $v)
    {
        if (trim($v)!="")
        {
            list($key,$value)=explode("=",$v,2);
            $tmp[trim($key)]=trim($value);
        }
    }
 
    $res=array();
    //режем ключи по параметрам
    foreach ($tmp as $key=>$value)
    {
        $keys=explode(".",$key);
        if (count($keys)!=1)
        {
            //тут будем делать подмассивчики
            $key=array_pop($keys);
            $first_key=array_shift($keys);
            if (!isset($res[$first_key]))
            {
                $res[$first_key]=array();
            }
            $pres=&$res[$first_key];
            while (count($keys)!= 0)
            {
                $tmp_key=array_shift($keys);
                if (!isset($pres[$tmp_key]))
                {
                    $pres[$tmp_key]=array();
                }
                $pres=&$pres[$tmp_key];
            }
            $pres[$key]=$value;
        }
        else
        {
            $res[$key]=$value;
        }
    }
    return $res;
}
print_r(read_conf("conf.ini"));
?>

Опубликовал:

Python: Простой пример использования twisted

16 июля 2009

Надо мне написать небольшой сервер, который будет принимать некие данные, сохранять их, а потом по определеным командам отдавать. Сейчас есть нечто такое же, только реализованное на LAMP, работает прямо скажем не очень быстро. Можно конечно сделать какое-то кеширование, memcache и т.д., но мне не хватает свободы маневра в текущей структуре, поэтому я решил таки переписать серверную часть, ибо клиентская вполне себе меня удовлетворяет.

Вообще решил сделать отдельный сервис, висящий на отличном от 80 порту и выполняющий все что мне надо. Писать решил с использование сетевого фреймворка twisted. Штука прикольная, но вот незадача, нормальной документации и примеров как то нету, того что на их сайте есть, мне явно не хватает, для того чтобы понять как и что нужно делать. Поэтому решил для начала написать простенький примерчик, который будет висеть и слушать запросы и в зависимости от url увеличивать или уменьшать внутренний счетчик.

Вот что получилось:

__author__="mrdaark"
__date__ ="$15.07.2009 21:31:01$"
 
from twisted.web import server, resource
from twisted.internet import reactor
import string
 
class Consult():
    count= 0
        def add(self,x=1):
            self.__class__.count+=x
        def remove(self,x=1):
            self.__class__.count-=x
 
class Server(resource.Resource):
    isLeaf = True
        def getChild(self, name, request):
            if name == '':
                return self
            return Resource.getChild(self, name, request)
        def render(self, request):
            urlpath=string.split(request.path[1:],'/')
            path=urlpath[ 0]
            if len(urlpath)>1:
                r=int(urlpath[1])
            else:
                r=1
 
            str='<html><head></head><body>'
            c=Consult()
            if (path=='add'):
                c.add(r)
            elif (path=='remove'):
                c.remove(r)
            str+= "x: %d<br />" % (c.count)
            str+='<a href="/add/1">add 1</a><br /><a href="/remove/1">remove 1</a></body></html>'
            return str
 
def main():
    site = server.Site(Server())
    reactor.listenTCP(8080, site)
    reactor.run()
 
if __name__ == "__main__":
    main()
 

Штука запускается, вешается на 8080 порт и принимает http запросы. Увеличивает и уменьшает внутренний счетчик в зависимости о второго параметра в урл, т.е. формат урл таков: /<функция>/<параметр>. По-умолчанию, параметр равен единице.

Вот такая штука вообщем получилась. Теперь буду усложнять этот примерчик, чтобы он сохранял и выводил список элементов, так и родится нужный мне функционал. 🙂

Опубликовал:

Python: RSS to Twitter

29 июня 2009

С недели 2 назад для одного хитрого сайта понадобилось сделать автоматический репост статей в твиттер. Решил не писать на php, а попробовать на python’е наваять. Откровенного говоря очень понравилось! Получилось очень просто и легко.

Написал наверное за пол часа, что с учетом того, что python я вообщем то не знаю совсем не плохо.

  1. #!/usr/local/bin/python
  2. # -*- coding: utf8 -*-
  3.  
  4. import urllib
  5. import libxml2
  6. import pickle
  7. import twitter
  8. import os
  9. from time import sleep
  10.  
  11. bit_api="bit.ly.api"
  12. bit_login="bit.ly.login"
  13. twit_login="name"
  14. twit_pass="pass"
  15. rss_url="http://feed"
  16.  
  17.  
  18. def shorten_url(long_url, login_user, api_key):
  19.     try:
  20.         longUrl = urllib.urlencode(dict(longUrl=long_url))
  21.         login = urllib.urlencode(dict(login=login_user))
  22.         apiKey = urllib.urlencode(dict(apiKey=api_key))
  23.  
  24.         encodedurl="http://api.bit.ly/shorten?version=2.0.1&%s&%s&%s" % (longUrl, login, apiKey)
  25.  
  26.         request = urllib.urlopen(encodedurl)
  27.         responde = request.read()
  28.         request.close()
  29.         responde_dict = eval(responde)
  30.         short_url = responde_dict["results"][long_url]["shortUrl"]
  31.         return short_url
  32.     except IOError, e:
  33.         raise "urllib error "
  34.  
  35.  
  36. if __name__ == '__main__':
  37.     doc = libxml2.parseFile(rss_url)
  38.     links=[]
  39.     for item in doc.xpathEval('//channel/item/link'):
  40.         links.append(item.content)
  41.  
  42.     titles=[]
  43.     for item in doc.xpathEval('//channel/item/title'):
  44.         titles.append(item.content)
  45.  
  46.     rss_path = os.path.join(os.path.dirname(__file__), 'rss.db')
  47.     file = open (rss_path)
  48.     old_links=pickle.load(file)
  49.     file.close()
  50.  
  51.     items=[]
  52.     f=0
  53.     for x in xrange(0,len(links)):
  54.         for old in old_links:
  55.             f=0
  56.             if (old==links[x]):
  57.                 f=1
  58.                 break
  59.         if (f==0):
  60.             items.append(x)
  61.  
  62.     api = twitter.Api(username=twit_login, password=twit_pass)
  63.  
  64.     for x in items:
  65.         title=titles[x].decode("utf8")
  66.         if len(title)<=120:
  67.             print "link %s: %s" % (x,links[x])
  68.             if x!=0:
  69.                 sleep(15)
  70.             api.PostUpdate(title+" "+shorten_url(links[x], bit_login, bit_api))
  71.  
  72.     file=open(rss_path,"w")
  73.     ser=pickle.dump(links,file)
  74.     file.close()
  75.  

Какие трудности вылезли в процессе:

1. Нужно как-то было не постить то что уже отправлено. Решилось сохранением списка ссылок в сериализованном виде в файл

2. Размер сообщение в твиттере не больше 140 символов, а надо бы в твитты еще и ссылки на статьи вставлять, притом что заголовки у статей я бы сказал не маленькие. Решилось регистрацией на bit.ly (сервис укорачивания ссылок) и собственно укорачивание. Не помню уже сам написал или с сайта их взял функцию, ибо там все так просто что даже неинтересно.

3. Невероятно, но встала проблема с кодировкой. Решилось за 5 минут гугления и пробования нескольких комбинаций. Что-то не понимал я откуда куда функции перекодируют. Вобщем вот так надо

title.decode(«utf8»)

4. Ну и задержку пришлось поставить, иначе bit.ly говорило зайдите позже 🙂

Дальше все это безобразие запихал в крон:

*/12 * * * * /usr/local/bin/python /usr/local/www/rss2twitter/rss2twit.py

За время пока это дело работает, уже сделан репост 1256 твиттов, так что красота.

А вообще все очень просто и легко, особенно учитывая что twitter api уже написано. хотя если бы его небыло, думаю я бы просто логинился, сохранял куки и постил обычным POST запросом.

Ну и файлик со скриптом на последок: rss2twit.tar.gz

З.Ы. с удовольствием выслушаю критику, потому как первое не Hello, world! приложение на python’е. 🙂

Опубликовал:

MySQL: базу знаю :)

6 мая 2009
Комментарии к записи MySQL: базу знаю :) отключены

Сегодня, не то чтобы от нечего делать, а так, прошел курс на сайте http://www.intuit.ru/ «Введение в СУБД MySQL». Прошел так, чтобы себя проверить, а то совсем самоучка, а тут хоть какое-то структурирование знаний. Честно скажу практически ничего нового для себя не вынес, пройти было на удивление легко, с первым тестом повозился (там теоретические знания по СУБД), никак он мне отлично ставить не хотел, все хорошо да хорошо. :))

Но вообщем все остальные, направленные на практику, сдал без проблем и сразу на отлично, вообщем-то как и экзамен. Местами правда у них в вопросах неоднозначные ответы, зависящие от нераскрытых входных данных, но это фигня 🙂

Cертификат даже себе выписал (правда только электронный). Посмотреть можно по адресу: http://www.intuit.ru/diploma/lQ2wte8s3eAw/P00057527/. Вообщем штука прикольная, надо будет поискать еще курсов, может чего дельного для себя найду, заодно и экспиренс прокачаю 🙂

Опубликовал:

В чем сила брат? В MySQL!

20 июня 2008
Комментарии к записи В чем сила брат? В MySQL! отключены

Сижу пишу систему управления правами доступа пользователей к разным функциям сайта.
В итоге для вывода всех пунктов меню в соответствии с выданными правами доступа наваял такой запрос:

SELECT rlp.name,CONCAT(rlp.label,’.php’) AS ‘url’ FROM (`right_list` AS rl JOIN `group_rights` AS gr ON (rl.id=gr.right)) JOIN `right_list` AS rlp ON (rl.parent=rlp.id) WHERE gr.type=»» AND rl.label=’read’ AND gr.group=1 ORDER BY rlp.order;

Аж самому понравилось 🙂

Опубликовал: