Monthly Archives: Вересень 2013

Лапки в bash та pss з awk

Є чудова команда для пошуку коду – pss. Ставиться через pip.

Тільки іноді біда – вона шукає рядки , і іноді те що вона знаходить – мінімізований JavaScript. А це означає що це всі файли зліплені в один рядок на кількасот кілобайт. Звісно мінімізований JavaScript мало кого цікавить, і його варто було б відфільтрувати. Але власник проекту сказав що функцію ігнорування такого коду реалізовувати не буде. Що не страшно, бо є труби і awk. AWK – це майже як grep, тільки з більшими можливостями, здається зовсім тюрінг-повна. Я якось рік тому почав її вивчати а потім забув. :)

І от, щоб відфільтрувати задовгі рядки, досить такої програми на awk:

lenght($0) < 1000


І от я пишу:

pss TextToSearch | awk "lenght($0) < 1000"

А воно не фільтрує!

Виявляється, за $0 – спершу береться bash. І echo "$0" дасть нам на виході слово "bash". А echo '$0' – сам "$0". Ну й зрозуміло що length(bash) – таки менше 1000, а якщо точно, то:

$ awk '{ print length(bash)}'
0

Напевне тому що змінна bash не визначена. Бо

$ awk '{ print length("bash")}'
4

awk_sed

І тому – при змішуванні таких екзотичних мов програмування, головне не переплутати що треба екранувати, і хто на які лапки як реагує.


Filed under: Інструменти, Кодерство Tagged: linux

PowerShell

PowerShell – оригінальна штука. В bash все – текст, тут все – об’єкти, навіть якщо виводиться як текст. Мені, як пітонщику подобається. :)

Але синтаксис – просто жах. Ось наприклад набір команд що дозволить показати на екрані IE, і ганяти його колами по екрану:

 function x_rot($t) { return [Math]::Round(([Math]::Cos($t / 1000.0) + 1) * 300) }
 function y_rot($t) { return [Math]::Round(([Math]::Sin($t / 1000.0) + 1) * 300) }

 $ie = New-Object -ComObject InternetExplorer.Application
 $ie.visible = $true
 for($i = 0; $i -lt 100000; $i++) { $ie.left = x_rot($i); $ie.top = y_rot($i) }

$i -lt 10000 розшифровується як i < 10000.


Filed under: Кодерство Tagged: windows

Цілковите пограбування блогу

І маленький експеримент щодо написання більш грамотного коду… В мене була ідея перетворювати *.py файли в публікації, а публікації – в виконувані *.py-файли, але поки що ця ідея все ще в статусі ідеї, тому тут просто буде код який можна оформити як пост:

'''
Невеликий скрипт який дозволяє завантажити собі на комп’ютер
який-небудь WordPress блог повністю. До останньої публікації.

Раніше я робив це за допомогою пошуку в ширину, MongoDB, регулярних виразів 
і багатьох інших зайвих речей. http://pastebin.com/e4SnvzAX

Зараз, дізнавшись що на wordpress.com є така 
річ як sitemap, я можу це робити набагато простіше.

'''

def main():
    '''
    Звідси програма починає роботу.
    Звісно, після того як модуль завантажить всі функції нижче.
    '''
    
    # Завантажмо наприклад мій блог:
    load_blog('http://bunyk.wordpress.com/')


def load_blog(url):
    ''' Завантажує блог в піддиректорію поточної директорії '''

    if not url.endswith('/'):
        # На всяк випадок гарантуємо що url закінчується слешем
        url = url + '/'

    # Нехай ім’я блогу - це найдовша частина url (адреса серверу зазвичай)
    blogname = max(url.split('/'), key=len)
    print(blogname)

    # Переконуємось що директорія куди ми завантажуватимемо блог існує.
    checkdir(blogname)

    sitemap = wget(url + 'sitemap.xml')

    # І зберігаємо кожну сторінку про яку пише sitemap:
    for page in iter_pages(sitemap):
        if is_article(page):
            save_page(page, blogname)

def is_article(url):
    ''' Якщо кількість слешів в url менше семи - це не стаття '''
    return sum(1 for c in url if c == '/') >= 7

def save_page(url, blogname):
    ''' Завантажити сторінку блога в файл '''
    name = url_to_name(url)
    print(name)
    with open(blogname + '/' + name, 'w', encoding='utf-8') as f:
        f.write(wget(url).decode('utf-8'))

def url_to_name(url):
    assert isinstance(url, str)
    # прибираємо адресу блогу і слеші з назви сторінки.
    name = ' '.join(url.split('/')[-4:]).strip()

    # розшифрувати кодування з %, якщо в URL кирилиця
    return unquote(name) 

try:
    from urllib.parse import unquote
except ImportError:
    from urllib import unquote


def wget(url):
    ''' Приймає url, повертає вміст того URL в кодуванні сторінки '''
    h, c = http.request(url)
    if h.status == 200:
        return c

''' Завантажувати сторінки будемо за допомогою httplib2 '''
import httplib2
http = httplib2.Http('.cache')


''' Для парсингу sitemap нам потрібна бібліотека для роботи з XML: '''
try:
    from lxml import etree
except ImportError:
    import xml.etree.ElementTree as etree

def iter_pages(sitemap):
    ''' Ця функція перетворює sitemap, даний як байти, на ітератор по url-лах '''

    assert isinstance(sitemap, bytes)

    tree = etree.fromstring(sitemap)

    ''' XPath селектор далі каже нам шукати всі елементи loc, в просторі імен
    sitemap всередині документа. '''
    return (
        element.text for element in
        tree.findall('.//{http://www.sitemaps.org/schemas/sitemap/0.9}loc')
    )


import os
def checkdir(directory):
    ''' Переконатись що директорія існує, а якщо ні - створити '''
    if not os.path.exists(directory):
        os.makedirs(directory)


if __name__ == '__main__':
    main()

Що далі?

Далі було б варто викинути html та залишити лише текст, і провести над ним якісь статистичні дослідження. Але я подумав що щоразу вручну знаходити xpath для головного вмісту сайту якось незручно і варто б це діло автоматизувати. А виявилось що виділення вмісту веб-сторінки – це тонка наука, і є задачею штучного інтелекту. І розв’язується не логічним підходом, а статистичним. Зокрема я накопав наступні роботи:

  1. 2007, alexjc The Easy Way to Extract Useful Text from Arbitrary HTML
  2. 2010, Roman Gelembjuk How to extract useful content from HTML page. Приємна несподіванка, автор статті з Франківська.
  3. 2010, Christian Kohlschütter, Peter Fankhauser and Wolfgang Nejdl: Boilerplate Detection using Shallow Text Features.

Але все це почитавши я подумав що для моїх потреб поки що XPath зійде…


Filed under: Кодерство, Павутина Tagged: блог, Python