Namecheap.com - Cheap domain name registration, renewal and transfers - Free SSL Certificates - Web Hosting

Регулярные выражения в Python

Thursday, November 18th, 2010

Регулярные выражения (они же регулярки, они же регэкспы) совершили настоящую революцию в обработке текстов, позволяя вести поиск и вставку текста используя так называемые паттерны – описывающие требуемый формат операции. Само по себе описание регекспов достаточно объемно, для повседневных задач можно даже изучить тему вполне поверхностно. Использовать регулярки, крайне удобно и быстро, несмотря на то что по скорости они проигрывают строковым и DOM функциям – тем не менее часто проще написать регулярку чем разрабатывать функцию. Само собой каждый уважающий себя язык программирования имеет реализацию регэкспов и Python не исключение. В качества классического примера :

def parse_proxy(page):
    """Parse proxies from webpage"""
    reg = re.compile("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}")
    proxy_list = reg.findall(page)
    return proxy_list

вытащить все прокси из кода вебстраницы. Простейшие регулярки несколько раз используются в прокси чекере.

Полезные сайты :
http://www.pcre.ru/ – типичные примеры, описание и конструктор который сильно облегчает процесс конструирования регулярных выражений.
http://www.regexlib.com/ – библиотека готовых регулярных выражений, сортировака по разделам. Очень полезный ресурс.
http://www.gskinner.com/RegExr/ – еще один конструктор регулярных выражений. Составь и проверь.
http://regexlib.ru/ – еще одна библиотека регулярок. на русском.

регулярные выражения

Использование регулярных выражений на Python.

Питон естественно предоставляет инструменты для работы с регулярными выражениям

http://docs.python.org/library/re.html
http://docs.python.org/dev/howto/regex.html – есть неплохой HOWTO

Библиотека регулярных выражений называется – re. Немаловажный момент – для строк с регулярным выражением нужно использовать префикс “r“, чтобы символы \ не преобразовывались в строковые специальные символы вроде \t, \n и т.д.

Использовать так :

match = re.search(ur"text", u"sometext and text")
print  "Re.seach : ", match.group()
exp = re.compile(ur"text")
match = re.finditer(exp, u"sometext and text")
print "Re.finditer : "
for item in match:
    print item.group(), item.span()

re.compile – компилирует регулярное выражение в regular expression object который может быть использован методами match() и search() и т.д. К выражению могут быть добавлены специальные флаги-модификаторы (вроде re.IGNORECASE).

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

group() возвращеает строку удовлетворяющую условию регэкспа.
start() Возвращает начальную позицию совпадения
end() Возвращает конечную позицию совпадения
span() Возвращает кортеж (tuple) – (start, end) в котором заданы позиции совпадения.

Следующий пример возвращает все числа из произвольной строки :

p = re.compile('\d+')
result = p.findall('1 2 3 yolochka gori, 23 yellow popugais')
print result

Целесообразность применения регулярных выражений.

Однако не стоит чересчур увлекаться регулярными выражениями (об этом говорят даже в официальном туториале python’а), зачастую бывает проще воспользоваться строковыми функциями – они быстрее (т.к. реализованы в виде небольших, хорошо оптимизированных C циклов). В моей практике бывали случаи когда самый простой путь был – через DOM вырезать нужный кусок и уже там работать регулярками (парсинг google images, например). Представим что вам нужно заменить слово “милиция” на “полиция”, для этого вполне подойдет функция re.sub, однако в РАЗЫ проще использовать replace() :

text = "Наша милиция нас бережет."
result = text.replace("милиция", "полиция")
print result

Разница между match() и search()

Функция match() только проверяет – есть ли совпадения с начала строки, в то время как search() будет сканировать на совпадения с паттерном всю строку целиком.

print(re.match('super', 'superstition').span())
print(re.match('super', 'insuperable'))
print
print(re.search('super', 'superstition').span())
print(re.search('super', 'insuperable').span())

(0, 5)
None

(0, 5)
(2, 7)

Удачных вам регулярных выражений. Стоит уделить изучению материалов по регекспам хотя бы несколько часов, поверьте ваши вложения времени с лихвой окупятся в будущем.

Функции map и zip и lambda. Python

Wednesday, November 17th, 2010

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

Функции map, zip и lambda в примерах.

Простая задача есть список a = [1, 2] и список b = [3, 4] одинаковой длины и нужно слить их парами. Проще простого – используя функцию zip :

a = [1,2]
b = [3,4]
print zip(a,b)
[(1, 3), (2, 4)]

или тройками :

a = [1,2]
b = [3,4]
c = [5,6]
print zip(a,b,c)
[(1, 3, 5), (2, 4, 6)]

или в более общем виде

list = [a, b, c]
print zip(*list)
[(1, 3, 5), (2, 4, 6)]

Звездочка * перед list как-бы говорит что передается список аргументов, т.е. Действовать эквивалентно тому как если бы передали a, b, c т.е. Можно даже так print zip(*[a, b, c]) результат не изменится.

Далее функция – map. Случаются ситуации, когда внезапно нужно применить какую-либо функцию к каждому элементу списка.
Нуб напишет так :

def f(x):
    return x*x
nums = [1, 2, 3]
results = []
for num in nums:
    results.append(f(num))
print results

Немного поизучавший мануалы так :

def f(x):
    return x*x
print [ f(num) for num in nums ]

Программист сделает проще :

def f(x):
    return x*x
print map(f, nums)

А вот тру-мэдскиллз кодер сделает следующим образом :

print map(lambda x: x*x, nums)

Последняя запись являет собой пример наиболее грамотного подхода. Дело в том, что когда человек пишет код как стихи в порыве вдохновения, крайне роляет скорость написания (отсюда растут корни трепетной любви многих питон кодеров к vim и emacs), а сильная сторона питона как раз в размере генерируемого кода – он очень компактный. Написать одну строчку естественно быстрее чем 7, да и изучать короткий код проще, однако написание подобного кода требует определенного навыка. Другая сторона медали – иногда про-devs очень любят писать в одну строчку целые последовательности достаточно сложных действий, да так что очень трудно понять что там происходит и что получается в конечном итоге.

Из примера понятно, что map применяет какую-либо функцию к списку и возвращает результат опять же в виде списка. Вы можете передать несколько списков, тогда функция (идущая первым параметром) должна принимать несколько аргументов (по количеству списков переданных в map) .

def f(x, y):
    return x*y

a = [1,3,4]
b = [3,4,5]
print map(f, a, b)
[3, 12, 20]

Жир, правда?

Однако если списки разной длины, т.е. Один короче другого, то он будет дополнен значениями None до нужной длины. Если убрать из списка b последнее значение – пример не будет работать, т.к. В функции f произойдет попытка умножения числа на None, а в питоне строгая типизация, что кстати выгодно отличает его от php, который в подобной ситуации работал бы дальше.
Поэтому если функция f достаточно объемна, неплохо бы проверять передаваемые значения. Например ;

def f(x, y):
    if (y == None):
        y = 1
    return x*y

Если же заместо функции стоит None – то map действует примерно так же как и zip, но если передаваемые списки разной длины в результат будет писаться None – что кстати очень уместно в некоторых моментах.

a = [1,3,4]
b = [3,4]
print map(None, a, b)
[(1, 3), (3, 4), (4, None)]

Теперь про лямбда функции в python. Они используются когда вам необходимо определить функцию, ведь часто (как в предыдущих примерах) функция настолько мала, что определять её отдельно смыла нет (ведь это лишние строчки кода и ухудшение читабельности).
Поэтому функцию можно определить “на месте” f = lambda x: x*x как бы говорит нам – принимает x, возвращает x*x

Так используя стандартные инструменты питона можно записать довольно сложные действия в одну строчку. К примеру функцию :

def f(x, y):
    if (y == None):
        y = 1
    return x*y

можно представить как :

lambda x, y: x * (y if y is not None else 1)

А теперь хорошо бы передавать списки отсортированные по длине – len(a) > (b) – проще простого – воспользуемся функцией sorted :

sorted([a, b], key=lambda x: len(x), reverse=True)

фунция sorted принимает список значений ([a,b] = [[1,2],[2,4,5]]) и сортирует по ключу key – который у нас задан функцией len(x) – возвращающей длину списка, сортируем в порядке убывания (reverse=True)

В конечном итоге вся операция записывается таким образом :

map(lambda x, y: x * (y if y is not None else 1), *sorted([a, b], key=lambda x: len(x), reverse=True))

списки a и b могут быть разной длины и передаваться в каком угодно порядке.
Лямбда-выражения удобны для определения не очень сложных функций, которые передаются затем другим функциям.

Прокси чекер на Python.

Sunday, November 14th, 2010

Как написать многопоточный прокси чекер на Python? Как нефиг делать =) Я уже писал немного о том как проверять прокси на alive, с тех пор прошло много времени и чекер немного усовершенствовался. Изначально я передал материал на форум Privatetalks, но теперь пришло время пополнить им блог. Исходные ходы поставляются как есть, в отрыве от контекста, собственно для тех кто шарит не составит труда доработать и реализовать многопоточность (на ActiveState и StackOverflow есть уже готовые решения по этой части).

Многопоточный чекер проксейВсе просто. Есть какая-то страница, которую нужно запрашивать через прокси, и проверят что там отдали. Помимо этой простейшей проверки на метод GET, есть еще проверки на POST и Cookie, некоторые прокси не держат, и поэтому часто бывают бесполезны для каких-то задач. Проверка на куки мне пока была не нужна, а вот проверку на POST я сделал.

TProxy – класс который обеспечивает работу с данными прокси. Такая тема в программировании называется – инкапсуляция.

На сервере нужно разместить несколько файлов с которыми будет взаимодействовать скрипт. Можно размещать и скрипт и эти файлы на одном сервере, я так и делал =) правда тогда будьте осторожны с многопоточностью у меня скрпит в 300 потоков бодро ложил апачи (не всегда, но бывало), на неслабом железе.
Предположим это index.php :

<html>
<head>
</head>
<body><h1>SIGNATURE</h1>
<h2>Real IP : xx.xx.xx.xx</h2>
<h2>IP : xx.xx.xx.xx</h2>
</body>
</html>

SIGNATURE – уникальный идентификатор страницы. должен совпадать с CHECK_STR. Еще нужно определить 2е “константы” CHECK_URL – урл где лежит вышеприведенная страница, и CHECK_MAX_TIMEOUT – максимальный таймаут (если отклик через прокси больше, то она помечается как bad) поставьте 2.0 для начала.
Как формируются Real IP и IP? Getting real IP address in PHP – вообщем с помощью этого кода нужно сформировать Real IP и IP.
А вот тут умные дядьки пишут как чекать геолокейшн – Check GEO Location. В принципе, я так понимаю таких сервисов много и можно долбить следующий если первый не вернул адекватный результат.

def check_proxy(proxy, need_country=False):
    """Check if proxy alive + anonymity and record proxy to file if we need this"""
    ip = TProxy(proxy)

    gt = urllib2.build_opener(urllib2.ProxyHandler({"http":ip.get_proxy()}))
    start_time = time.time()
    try:
        result = gt.open(CHECK_URL, timeout=CHECK_MAX_TIMEOUT)
        result = result.read()
    except (urllib2.URLError, socket.timeout, httplib.BadStatusLine, httplib.InvalidURL):
        ip.set_alive_status(False)
        return ip
    except:
        ip.set_alive_status(False)
        return ip

    ip.set_alive_status(True)
    ip.set_timout(time.time() - start_time)     # proxy response time

    # get ip and real ip values. check for anonymity
    search = re.compile(CHECK_STR)
    pattern = re.search(search, result)

    if pattern != None:
        ip.set_alive_status(True)
        search = re.compile("IP : \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}")
        ips = re.findall(search, result)
        # extract ip and real ip values from page
        if ips != []:
            try:
                real_ip = ips[0]
                given_ip = ips[1]
                if real_ip == given_ip:
                    ip.set_anonymous_status(True)
            except:
                ip.set_alive_status(False)
                return ip

        # check country
        if need_country:
            try:
                response = gt.open('http://api.hostip.info/get_html.php?ip=%s' % ip.get_host(), timeout=5).read()
                country = re.search('Country: (.*)', response)
                if country <> "":
                    ip.set_country(country.group(1))
                else:
                    ip.set_country('undefined')
            except:
                ip.set_country('undefined')
    return ip

Теперь как проверить на POST.

def generate_random_str(length=10):
    str = string.lowercase+string.digits
    return ''.join(random.sample(str, length))

def check_proxy_for_post(proxy):
    token = generate_random_str(20)
    try:
        gt = urllib2.build_opener(urllib2.ProxyHandler({"http":proxy}))
        post_data = urllib.urlencode({'zpost' : token})
        response = gt.open(CHECK_URL + "post.php", post_data, timeout=POST_MAX_TIMEOUT).read()
        # check token
        print response
        search = re.compile(token)
        pattern = re.search(search, response)
        if pattern != None:
            return True
        else:
            return False
    except HTTPError, e:
        print "Http error"
        return False
    except URLError, e:
        print "Url error"
        return False
    except:
        print "Unknown error"
        return False

Легко встраивается в функцию check_proxy приведенную выше. Нужно только немножко пошевелить мозгами.
в файл index.php добавляется форма :

<form action="post.php" "method="post">
<input type="text" name="zpost" value="post check">
<input type="submit" value="Check POST method">
</form>

В ту же папочку аккуратно ложится файлик

<html>
<body>
<h1><?php echo $_POST["zpost"]; ?></h1>
</body>
</html>

Вообщем код легко собирается в готовый продукт, добавляются фичи по вашему вкусу и вперед ура.
Кстати говоря готовый код недавно обнаружил на гитхабе – чекер прокси. Оттуда тоже можно взять несколько идей.

А еще нужно не жадничать и быть аккуратным т.к. ДЦ может абузить по подозрению в Netscan.

Понравилась статья? Зарегайся на форуме privatetalks – общайся с профессионалами.

Самый быстрый способ удалить дубли из списка. Python

Sunday, November 14th, 2010

Задача классическая. Удалить повторы из какого-либо списка. Самый быстрый вариант сделать так :

def uniq(seq):
    """The fastest way to unique list"""
    seen = set()
    seen_add = seen.add
    return [ x for x in seq if x not in seen and not seen_add(x)]

Составление случайной последовательности из списка.

Saturday, November 13th, 2010

Часто встречающаяся задача – получить случайную последовательность, случайной длинны из какого-либо набора данных. Например – 5-10 кейвордов из списка кеев в несколько тысяч, или выбор последовательности действия для бота имитирующего поведение человека. Ну в простейшем варианте – все просто :

import random
data = ['add_friends', 'post_story', 'vote', 'comment']
chain = random.sample(data, 2)

А если хочется задать вероятность наступления события?

import random

def get_random_chain(chain, min_max=[1,1]):
    """ Get random chain from list """
    items_chain = []
    random.seed()
    for item, num in chain.iteritems():
        items_chain.extend([item] * num)
    random.shuffle(items_chain)
    chain_len = random.randint(min_max[0], min_max[1])
    return random.sample(items_chain, chain_len)

Вот так использовать (исходная последовательность задается в виде словаря key : value – где value вероятность наступления события) :

ACTIONS = {
    "post" : 20,
    "vote" : 80
}
what_to_do = get_random_chain(ACTIONS, [5,10])

Получить случайную цепочку действий длинной в данном случае от 5 до 10 элементов.
Обратите внимание длинна цепочки может быть сколь угодно длинной и превышать исходную последовательность.

Удалить html тэги из строки. Python Edition.

Saturday, November 13th, 2010

Вам нужен http://www.crummy.com/software/BeautifulSoup/ – отличная штука для работы с html/xml документами, работает даже если xml кривой. Очень часто встречающаяся задача – удалить html тэги из строки.

from BeautifulSoup import BeautifulSoup

''.join(BeautifulSoup(page).findAll(text=True))

Так же можно заюзать уже готовый код от Lorien’а (помните про open source?) – clean.py, не забудьте импортировать в проект так же и htmldata.py

Бот совершает покупки в сети

Friday, November 12th, 2010

Прочитал вот это. На первый взгляд кажется – ну и что такого? Бот совершает покупки в онлайн шопе и пишет отчеты в твиттер. Тем не менее это инновация, способов применения ей можно найти массу, если приложить голову ) Такие разработки всегда привлекают внимание.

Итак собственно бот написан на Python и для поиска товаров использует API – http://developer.trademe.co.nz/api-documentation/. Бот запускается каждый день в 8 часов утра и имеет в день по 1$ “карманных денег”, котрые однако он может и не потратить (а может и потратить шанс 1/3), а сэкономить чтобы купить более дорогую покупку. Методы поиска :

Бот сканирует категории товаров, там он ищет слова – free shipping, и сортирует по самым новым поступлениям, но не более 100 итемов на категорию. Далее он сортирует по ценам стараясь потратить не больше 50% сбережений. Попутно проверяя предмет на уникальность. Полностью нехитрый алгоритм выглядит так.

The method it uses to select items:

  • It has a bunch of top-level categories it looks in.
  • For each of these categories, it searches for the term “Free shipping”, specifying both pay-now and buy-now, sorting by newest listings, with a maximum of 100 items returned per category.
  • For each of these items, it filters on buy-now price. It tries to spend at least 50% of its savings.
  • For each of the surviving items, it looks up the individual auction details to find its shipping information so it can filter on free shipping. Despite searching for the term ‘free shipping’ to start, only a small number of items have this.
  • At this point I have a list of items that match the price requirements, and can be bought with a credit card buy-now.
  • I then sort this list by ‘rarity’ – doing a search for the item title, and finding the item that returns the least results. As the objective here is to buy strange and esoteric things, rarity is preferred.
  • Finally I buy the rarest item and subtract its cost from the bots savings.

Хранение настроек Python

Wednesday, November 10th, 2010

Часто настроек в приложении может быть дофига и невольно задумываешься о том, чтобы вынести их в отдельный файл – файл настроек. Бывает программисты по инерции начинают писать код который будет считывать и обрабатывать этот файл, и бывает даже строковыми методами. Однако в питоне ничего не мешает нам создать файл вроде settings.py и исполнять его на уровне кода.
Вот к примеру файл settings.py :

import os.path as path

template_dir = path.join(path.dirname(__file__), "templates")

user_record = {
    'id' : 1,
    'mail' : "xyu@gmail.com",
    'pass' : "1234"
}

А вот так его можно вызывать из кода :

import settings

def main():
    print settings.template_dir

if __name__ == "__main__":
    main()

или так (по модному) :

def main():
    mod = __import__("settings")
    print getattr(mod, 'template_dir')

if __name__ == "__main__":
    main()

Проверка количества проиндексированных страниц в Google

Tuesday, September 7th, 2010

Как определить кол-во проиндексированных страниц в гугле? реализация на Python. Недавно нужно было срочно, написал :

import urllib
import re

from urllib2 import urlopen
from urlparse import urlparse
from urllib import FancyURLopener

class GOpener(FancyURLopener):
    version = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6'

def web_getpage(url):
    g_opener = GOpener()
    page = g_opener.open(url)
    return page.read()

def get_index(url):
    request = 'http://www.google.com/search?q=site:' + url
    # About 105,000,000 results
    index = 0
    try:
        gs = web_getpage(request)
        p = re.compile('About (.*) results')
        index = int(p.findall(gs)[0].replace(",", ""))
    except SearchError, e:
        index = -1
        #print "Search Failed : %s" % e
    finally:
        #print "Index: %d\tURL: %s" % (int(index), url)
        return index

Проверка подключения к интернету

Thursday, September 2nd, 2010
from urllib2 import urlopen
""" Returns True if we appear to have an internet connection or False.
    It defaults to using google as a test server, but you can supply an alternative if you want."""
def isonline(reliableserver='http://www.google.com'):
    try:
        urlopen(reliableserver)
        return True
    except IOError:
        return False

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

Проверка Google PR на Python

Tuesday, August 31st, 2010

Собственно рабочая функция проверки Google Page Rank :

import urllib, sys

def get_pagerank(url):
    hsh = check_hash(hash_url(url))
    gurl = 'http://www.google.com/search?client=navclient-auto&features=Rank:&q=info:%s&ch=%s' % (urllib.quote(url), hsh)
    try:
        f = urllib.urlopen(gurl)
        rank = f.read().strip()[9:]
    except Exception:
        rank = 'N/A'
    if rank == '':
        rank = '0'
    return rank

def  int_str(string, integer, factor):
    for i in range(len(string)) :
        integer *= factor
        integer &= 0xFFFFFFFF
        integer += ord(string[i])
    return integer

def hash_url(string):
    c1 = int_str(string, 0x1505, 0x21)
    c2 = int_str(string, 0, 0x1003F)

    c1 >>= 2
    c1 = ((c1 >> 4) & 0x3FFFFC0) | (c1 & 0x3F)
    c1 = ((c1 >> 4) & 0x3FFC00) | (c1 & 0x3FF)
    c1 = ((c1 >> 4) & 0x3C000) | (c1 & 0x3FFF)

    t1 = (c1 & 0x3C0) << 4
    t1 |= c1 & 0x3C
    t1 = (t1 << 2) | (c2 & 0xF0F)

    t2 = (c1 & 0xFFFFC000) << 4
    t2 |= c1 & 0x3C00
    t2 = (t2 << 0xA) | (c2 & 0xF0F0000)

    return (t1 | t2)

def check_hash(hash_int):
    hash_str = '%u' % (hash_int)
    flag = 0
    check_byte = 0

    i = len(hash_str) - 1
    while i >= 0:
        byte = int(hash_str[i])
        if 1 == (flag % 2):
            byte *= 2;
            byte = byte / 10 + byte % 10
        check_byte += byte
        flag += 1
        i -= 1

    check_byte %= 10
    if 0 != check_byte:
        check_byte = 10 - check_byte
        if 1 == flag % 2:
            if 1 == check_byte % 2:
                check_byte += 9
            check_byte >>= 1

    return '7' + str(check_byte) + hash_str

print get_pagerank("http://twitter.com")

Легкая IDE для Pyhton

Tuesday, August 24th, 2010

Не так давно услышал про такую IDE как Pyscripter. Скачал отсюда, утсановил. Вообщем пара слов : легче чем NetBeans определенно. Рекомендую.

pyscripter IDE

Время выполнения функции python

Monday, June 21st, 2010

Бывает необходимо замерить время выполнения скрипта или функции. Сделать это можно следующим образом :

start = time.time()
function_name()
print "Elapsed Time: %s" % (time.time() - start)

function_name() <<—- функция время выполнения которой нужно замерить

My blog is Do-Follow


Пишу код, делаю сайты.
Check out my about.me profile!

парсинг сайтов, форумов, интернет магазинов

Want to subscribe?

istinspring twitter account
istinspring facebook account

 Subscribe in a reader Or, subscribe via email:
Enter your email address:  
Find entries :