Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

Posts Tagged ‘Python

Випадковий ідентифікатор в Python

with 4 comments

Можна отримати так:

import random
def random_id(length=6):
   return ''.join(
        random.choice(string.lowercase)
        for i in range(length)
    )

###############
>>> random_id()
'kqxmua'

Якщо треба особливо оформлений, як от IP, чи MAC-адреса, то можна зробити перетворення:

def asmac(val):
    """Convert a byte string to a MAC address string.  """
    return ':'.join('%02X' % ord(c) for c in val)

def random_mac():
    return asmac(random_id())

###################
>>> random_mac()
'78:71:6A:72:6E:63'

Але такі ідентифікатори як “kqxmua” нормальній людині важко запам’ятати, бо вони не асоціюються з жодними поняттями. Ну окрім частинки “ua”, але й то вона туди випадково потрапила. Проте, в Linux можна легко отримати випадкове слово, бо в ньому є словник:

def random_word():
    return random.choice(
        open('/usr/share/dict/words').readlines() # жертиме пам’ять! 
    ).strip()

#################
'.join(random_word() for i in range(5))
'hermitical, Canter, Paryavi, mergences, Mind'

Хоча я знайомий лише з “hermitical” та “mind”, але асоціації вже легше побудувати, правда?

Written by bunyk

Березень 18, 2015 at 12:34

Опубліковано в Всяке, Кодерство

Tagged with ,

Зберегти всю стіну групи VK в таблицю

leave a comment »

Якось під час чергового наближення економічної кризи захотілось проаналізувати ціну нерухомості в Львові. А ще, в той же час я наткнувся на документацію API Вконтакті. А так як своє житло я шукав в тому числі і в тій соціальній мережі, то вирішив проаналізувати наприклад спільноту vk.com/nomakler.

Ну, проаналізувати це легко сказати – важче зробити. Як витягти з повідомлення ціну, і як відрізнити попит від пропозиції? Га?

Але є половинний результат – ФСБ мусило поділитись частиною своєї бази даних розміром в 40450 оголошень. Тут можна її завантажити як tsv, xls чи інший зручний для вас формат. Може комусь, хто захоче збільшити конкуренцію серед львівськи маклерів/ріелторів знадобиться.

А якщо кому потрібна інформація з інших груп – ось скрипт. Викликаєте функцію save2tsv з назвою групи і назвою файлу в який писати – і чекаєте поки завантажиться.

import requests
import json
from pprint import pprint
from itertools import islice
from datetime import datetime

from butils.csv_wrapper import UnicodeWriter

class APIError(Exception):
    pass

def vk(method, **kwargs):
    '''
        https://vk.com/dev/methods
    '''
    r = requests.get(
        'https://api.vk.com/method/%s' % method,
        params=kwargs
    )
    js = json.loads(r.text)
    if js.get('error'):
        raise APIError(js['error']['error_msg'])

    return js['response']


def get_users(ids, known_users={}):
    request_ids = [i for i in ids if i not in known_users]
    if request_ids:
        user_ids=','.join(str(i) for i in request_ids if i > 0)
        if user_ids:
            users = vk('users.get', user_ids=user_ids)
        else:
            users = []
        group_ids=','.join(str(-i) for i in request_ids if i < 0)
        if group_ids:
            groups = vk('groups.getById', group_ids=group_ids)
        else:
            groups = []
        for user in users:
            known_users[int(user['uid'])] = dict(
                first_name = user['first_name'],
                last_name = user['last_name'],
            )
        for group in groups:
            known_users[-int(group['gid'])] = dict(
                first_name = group['name'],
                last_name = group['gid']
            )
    return known_users


def get_wall(domain):
    count = 50
    offset = 0
    def get_with_offset(offset):
        nonlocal count
        print('get_with_offset(%s)' % offset)
        total = vk('wall.get',
            domain=domain,
            count=1,
        )[0]
        off = total - offset - count
        if off < 0:
            count = count + off
            off = 0
        return vk('wall.get',
            domain=domain,
            count=count,
            offset=off,
        )[1:][::-1] # remove first and reverse

    while True:
        posts = get_with_offset(offset)
        offset += count
        users = get_users(p['from_id'] for p in posts)
        for p in posts:
            yield p, users[p['from_id']]
        if count < 50:
            return


def save2tsv(domain, dst):
    with UnicodeWriter(dst, encoding='utf-8', delimiter='\t') as writer:
        writer.writerow((
            'ID',
            'Datetime',
            'First name',
            'Last name',
            'Text',
            'Type',
            'Comments',
            'Reposts',
            'Likes',
        ))
        for p, user in get_wall(domain):
            writer.writerow(list(map(str, (
                p['id'], # ID
                datetime.fromtimestamp(p['date']), # Datetime
                user['first_name'], # First name
                user['last_name'], # Last name
                p['text'], # Text
                p['post_type'], # Type
                p['comments']['count'], # Comments
                p['reposts']['count'], # Reposts
                p['likes']['count'], # Likes
            ))))

# save2tsv('nomakler', 'nomakler.tsv')

Written by bunyk

Березень 8, 2015 at 17:38

Опубліковано в Кодерство, Павутина

Tagged with

Пишемо простий keylogger для Linux

with 6 comments

Кейлоггер це така шкідлива корисна програма яка записує всі натискання клавіш користувачем в будь-яких інших програмах операційної системи. І сьогодні ми вивчатимемо як таке написати. Якщо ви навчитесь працювати з файлами в Linux – ви зможете все. Серйозно. Тому я колись планую детально вивчити і написати про файли там.

Все в лінуксі файл, і клавіатура – теж. Щоб знати який – відкриваємо /proc/bus/input/devices. Нас цікавить абзац в якому написано про клавіатуру, і він зазвичай містить рядок EV=120013, тому можете пошукати його. Коли знайшли абзац, читаємо в ньому рядок H: Handlers=sysrq kbd event3.

Можна дістати однією командою:

cat /proc/bus/input/devices | grep EV=120013 -B 2 | grep event

Слово event3 означає що нам треба читати файл пристрою /dev/input/event3.

Так як в заголовку було слово простий, ми спростимо собі життя і поставимо деяку бібліотеку:

pip-2.7 install evdev

Прочитати решту цієї замітки »

Written by bunyk

Березень 8, 2015 at 00:29

Опубліковано в Кодерство

Tagged with ,

Простий HTTP клієнт і сервер на сокетах

with 12 comments

В Python є мільйони бібліотек для роботи з HTTP, але так як HTTP працює через TCP/IP, то всі вони працюють використовуючи штуку яка називається socket. Сокет – це дуже низькорівнева річ, що нагадує файл (але не пітонівський об’єкт файлу, і навіть не сішний, а доступ до файлу через дескриптор, за допомогою викликів операційної системи open, write та read).

Хоча, досить вже вас страшити, ми просто зробимо це спрощено, як вправу, і основу для створення деяких інструментів для тестування та зневадження мережевих програм.

Клієнт

# coding=utf-8

import socket
import sys

def main():
    get(sys.argv[1])

def get(url):
    # Парсимо url на домен і GET запит в межах домену
    if url.startswith('http://'):
        url = url[len('http://'):]
    domain, query = url.split('/', 1)

    # створюємо сокет
    clientsocket = socket.socket(
        socket.AF_INET, socket.SOCK_STREAM
    )
    # AF_INET - аднесна сім’я сокета - інтернет (бувають юнікс і всілякі інші)
    # SOCK_STREAM - потоковий сокет (TCP). Бувають дейтаграмні (UDP).

    # з'єднуємось з 80-тим портом сервера:
    clientsocket.connect((domain, 80))

    # відправляємо туди всі дані запиту (поки не відправляться)
    # метод send() відправляє певну кількість байт і повертає ціле число - 
    # скільки відправив. Далі треба вручну досилати, нас ця зайва робота
    # не цікавить.
    clientsocket.sendall(query_template % (query, domain))

    while True:
        # отримуємо по 4096 байт даних
        # кажуть для максимальної продуктивності треба просити невелику 
        # степінь двійки байт
        data = clientsocket.recv(4096)

        # в stderr пишемо склільки насправді отримали (це цікаво)
        sys.stderr.write('DEBUG: Got %s bytes\n' % len(data))

        if len(data) == 0: # якщо даних більше нема - 
            break # то можна закінчувати

        # в stdout - наші дані
        sys.stdout.write(data)


    clientsocket.close() # закриваємо сокет

query_template = '''GET /%s HTTP/1.1
Host: %s
User-Agent: python
Connection: close

'''.replace('\n', '\r\n')
# В HTTP рядки заголовків розділяються \r\n
# Кінець заголовків позначається порожнім рядком, тому якщо його забути
# сервер буде довго чекати поки ви закінчите, а потім пришле
# 408 Request Timeout
# Connection: close - каже йому що можна закрити сокет після того як дані отримано.


if __name__ == '__main__':
    main()

Тест:

$~ python client.py https://bunyk.wordpress.com/
DEBUG: Got 387 bytes
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Fri, 06 Mar 2015 07:39:41 GMT
Content-Type: text/html
Content-Length: 178
Connection: close
Location: https://bunyk.wordpress.com/
X-ac: 1.fra _sat

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
DEBUG: Got 0 bytes

На жаль в наш час мало що можна отримати, бо всі хочуть перенаправити тебе на https, а він складніший за http, але й по самій відповіді 301 бачимо що клієнт працює.

Тепер складніше, але не набагато:

Сервер

Сервер, на відміну від клієнта, який створює з’єднання, посилає запит, читає відповідь і закриває з’єднання, повинен відкрити порт, і постійно очікувати з’єднань на ньому. Якщо з’єднання відбувається – прочитати запит і послати відповідь.

# coding=utf-8

import socket

def main():
    HttpServer(8080).run()

class HttpServer(object):
    def __init__(self, port=8000):
        # створюємо абсолютно такий самий сокет як і в клієнта
        self.socket = socket.socket(
            socket.AF_INET, socket.SOCK_STREAM
        )
        # але замість того аби приєднуватись до сокета на чужому 
        # сервері - приєднуємось до сокета на нашому:
        self.socket.bind(('', port))
        # і очікуємо з’єднання 
        # 5 - розмір черги з’єднань
        self.socket.listen(5)
        print 'Serving at', port

    
    def run(self):
        try:
            while True:
                # прийняти наступне з’єднання
                (conn, address) = self.socket.accept()
                print 'Connection from', address
                data = conn.recv(1024)
                # прочитати 1024 байт запиту 
                # (припустимо що цього буде досить)

                # послати назад заголовки відповіді HTTP 200 OK, 
                # і вміст - отриманий запит
                conn.send(http_ok(data))
                # І закриваємо з’єднання з клієнтом
                conn.close()
        except KeyboardInterrupt:
            print 'Bye!'

    def __del__(self):
        # Сокет треба закрити, щоб при наступному запуску
        # нам не сказали що він вже зайнятий.
        self.socket.shutdown(socket.SHUT_RDWR)
        self.socket.close()


def http_ok(content):
    return (
        'HTTP/1.0 200 OK\r\n'
        'Content-Type: text/html\r\n\r\n'
        '<html><body><pre>%s</pre></body></html>'
        % content
    )

if __name__ == '__main__':
    main()

Тепер, коли ми запустимо сервер, і відкриємо в браузері localhost:8080, то побачимо там щось схоже на:

GET / HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:35.0) Gecko/20100101 Firefox/35.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: __utma=111872281.1988111138.1417337610.1419706230.1419710582.13; __utmz=111872281.1417337610.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Connection: keep-alive

Цей чарівний lo-інтерфейс

Найбільш радісним для мене було відкриття того, що якщо ми перейдемо за адресою 127.123.123.123:8080, чи будь-якою іншою виду 127.*.*.* (окрім 127.255.255.255), ми отримаємо відповідь:

GET / HTTP/1.1
Host: 127.123.123.123:8080

А це означає що ми можемо одним нашим сервером імітувати 16 хостів. HTTP передає заголовок HOST, саме тому, що один сервер може обробляти дані кількох хостів (які називаються віртуальними), і йому потрібно їх якось розрізняти.

Тут з’являється інша проблема – якщо ми хочемо імітувати кілька тисяч хостів, але не HTTP, а наприклад SNMP. В SNMP такого поля як адреса хоста на який ми послали запит нема, а так як всі потрапляють на один і той самий localhost, то й відрізнити їх нема як. Зате звісно таке поле є в пакету IP, і здається є спосіб до заголовків цього протоколу дістатись, використовуючи дещо, що називається raw socket. Проте це чорна магія якою я поки що ще не оволодів, тому залишу це до наступного разу.

Written by bunyk

Березень 7, 2015 at 00:46

Опубліковано в Кодерство, Павутина

Tagged with ,

Scala partition в Python

with 5 comments

Вперше сьогодні в мене був момент “А якби я писав на Scala…”. Задача – є список з мухами і котлетами вкупі. Треба мухи окремо, котлети окремо.

В Python класично це так:

Frikadellen = [x for x in AllesZusammen if IstFrikadelle(x)]
Fliegen = [x for x in AllesZusammen if not IstFrikadelle(x)]

В Scala:

(Frikadellen, Fliegen) = AllesZusammen partition IstFrikadelle

Scala, окрім того що коротша, виграє тим що проходиться по списку лише раз.

Але StackOverflow як завжди дає жару:

Frikadellen, Fliegen = [], []
for x in AllesZusammen:
    (Fliegen, Frikadellen)[IstFrikadelle(x)].append(x)
    # або
    # (Frikadellen if IstFrikadelle(x) else Fliegen).append(x)

Це вже краще, але все одно було б добре якби до списку додали метод partition. Може б то Ґвідо поскаржитись?

Written by bunyk

Лютий 27, 2015 at 00:04

Опубліковано в Кодерство

Tagged with ,

Як видалити платні речі з AWS

with 3 comments

За січень привалив рахунок на 4 з копійками долари, через те що якісь тестери настворювали в моєму тестовому аккаунті на AWS волюмів і лоад балансерів. А так як це вже не вперше, і мені надоїло перевіряти кожен регіон на наявність вказаних в білінгу пунктів, вирішив написати для цієї справи скрипта. Правда якщо ним захочете користуватись ви – треба ще розширити його інстансами, бакетами і всім іншим за що амазон може здирати бабло.

Дивуюсь чому вони замість повідомлення про перевищення бюджету не зроблять функцію автоматичного вимикання зайвих послуг.

Ах, скрипт:

from boto.ec2.connection import EC2Connection
import boto.ec2.elb

def main():
    ec2 = EC2Connection()
    for region in ec2.get_all_regions():
        print 'Region:', region.name
        process_region(region)

def process_region(r):
    c = r.connect()

    for volume in c.get_all_volumes():
        print '\tVolume:', volume.id
        if volume.attachment_state() == u'attached':
            volume.detach()
        volume.delete()

    c = boto.ec2.elb.connect_to_region(r.name)
    for lb in c.get_all_load_balancers():
        print '\tLoad balancer:', lb

if __name__ == '__main__':
    main()

Written by bunyk

Лютий 9, 2015 at 23:39

Опубліковано в Кодерство

Tagged with ,

Трактат про Zope Component Architecture

with one comment

Zope – це дуже-дуже старий фреймворк (історія почалася ще з 1995), але деякі його частини, а іноді і сам він використовуються в різних системах і досі. Наприклад Twisted використовує інтерфейси Zope (їх свідчення). Біда з ним в тому, що якась пристойна інструкція в інтернеті не доступна. Може вона й була там колись, але на жаль посилання не завжди працюють, а з такою старовиною як Zope – дуже часто ведуть в тупик 404. Своїм трактатом постараюсь цю біду хоч трохи виправити.

Ах, ще цікавий факт, ZCA з’явилась в Zope 3 (BlueBream), при спробі переписати все “правильно”, ігноруючи зворотню сумісність. Таким чином ситуація трохи нагадує ситуацію з Python 3. Тільки Python 3 з’явився в 2008, і здається таки має деякі шанси вижити, а от Zope 3 (BlueBream) – в 2004, і від нього відросли інші фреймворки, наприклад BFG, який об’єднався з Pylons і став Pyramid. Але цю всі історію дуже цікаво розповідає Пол Еверітт, один з тих хто все це почав. Він пояснить вам що Zope ще не вмерла, вона просто спить:

А тут мова піде лише про таку частинку Zope, як ZCA. І ми будемо писати код. З нуля!
Прочитати решту цієї замітки »

Written by bunyk

Грудень 13, 2014 at 19:08

Опубліковано в Кодерство

Tagged with

Follow

Get every new post delivered to your Inbox.

Join 258 other followers