Час­то нам при­ходит­ся совер­шать со сво­им iPhone монотон­ные и доволь­но скуч­ные манипу­ляции, которые зас­тавля­ют нас с завистью смот­реть на дес­кто­пы с их без­гра­нич­ными воз­можнос­тями нас­трой­ки, скрип­тинга и авто­мати­зации дей­ствий. Да что там дес­кто­пы — даже на поль­зовате­лей Android с их вез­десущим Tasker’ом, с помощью которо­го мож­но зап­рограм­мировать смар­тфон на что угод­но. В iOS сущес­тво­вание подоб­ных при­ложе­ний невоз­можно, но у нас есть неболь­шая лазей­ка.
 

Введение

В этой статье я хочу рас­ска­зать о Pythonista — сре­де раз­работ­ки на язы­ке Python (вер­сии 2.7.5) для iOS, которая поз­воля­ет в том чис­ле писать пол­ноцен­ные при­ложе­ния с гра­фичес­ким интерфей­сом. Одна­ко мы будем исполь­зовать ее для нес­коль­ко иных целей — для соз­дания прос­тых под­собных скрип­тов, которые будут авто­мати­зиро­вать рутин­ные опе­рации.

Pythonista Shell
Pythonista Shell

Pythonista вклю­чает в себя мно­жес­тво пре­дус­танов­ленных биб­лиотек, в том чис­ле те, что помогут нам получить дос­туп к фун­кци­ональ­нос­ти iOS. Как при­мер мож­но при­вес­ти clipboard, поз­воля­ющий читать и писать в буфер обме­на, contacts для работы с адресной кни­гой, keychain, location и дру­гие.

info

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

Кро­ме встро­енных, нам так­же понадо­бят­ся сто­рон­ние Python-модули. Для Pythonista сущес­тву­ет два ана­лога всем извес­тно­го pip. Это pipista 2.0 и Pypi. Что­бы уста­новить пакет с помощью пер­вого, необ­ходимо сох­ранить скрипт в кор­невой каталог и выпол­нить такую коман­ду:

import pipista
pipista.pypi_install('Name_of_library')

У этой биб­лиотеч­ки есть так­же фун­кции pypi_download(), pypi_search() и pypi_versions(), что поз­воля­ет счи­тать ее пол­ноцен­ной заменой pip. Вто­рой уста­нов­щик тре­бует более чет­ких зап­росов. Нап­ример, необ­ходимо ука­зать вер­сию пакета — это удоб­но, если по какой‑то при­чине не хочешь исполь­зовать пос­леднюю вер­сию.

from Pypi import Installer
Installer('Name_of_library', 'Version').install()

У это­го уста­нов­щика так­же есть допол­нитель­ные фун­кции.

Устанавливаем пакет с помощью Pipista
Ус­танав­лива­ем пакет с помощью Pipista

Как запустить скрипт с главного экрана

Для это­го есть две воз­можнос­ти: Pythonista Shortcut и Launch Center Pro. В пер­вом слу­чае все прос­то: дос­таточ­но зай­ти с девай­са на сайт, ввес­ти имя скрип­та и аргу­мен­ты, нажать на кноп­ку Create Shortcut, затем сох­ранить эту стра­ницу на рабочий стол, исполь­зуя стан­дар­тные фун­кции Safari.

Вто­рая прог­рамма куда инте­рес­ней. Что­бы запус­тить скрипт из нее, необ­ходимо соз­дать событие и в поле URL про­писать вот такую строч­ку: «pythonista://script_name?action=run&args=», где script_name — имя скрип­та с уче­том иерар­хии катало­гов, а пос­ле args= необ­ходимо перечис­лить аргу­мен­ты (если они есть). Так­же при­сутс­тву­ет воз­можность запус­ка по вре­мени или с опре­делен­ной регуляр­ностью.

Есть и воз­можность упа­ковать скрипт в пол­ноцен­ное iOS-при­ложе­ние. Для это­го дос­таточ­но ска­чать ар­хив с про­ектом XCode с офи­циаль­ного сай­та и заменить стан­дар­тный скрипт с Hello, world на свой. Пос­ле это­го мож­но соб­рать этот про­ект в XCode и запус­тить на симуля­торе, а если есть акка­унт раз­работ­чика Apple, то и на гад­жете.

Все скрипты в Launch Center Pro
Все скрип­ты в Launch Center Pro
 

Скрипты

На­пишем нес­коль­ко скрип­тов, дабы облегчить жизнь нам и нашим близ­ким. Воз­можно, некото­рые из них (или все) для кого‑то покажут­ся бес­полез­ными, но зато они дают пред­став­ление о том, что мож­но сде­лать с помощью Pythonista, и могут выс­тупать в качес­тве некой базы для тво­их экспе­римен­тов. Все­го скрип­тов девять, и они очень раз­нооб­разны.

Редактор кода
Ре­дак­тор кода
 

Быстрая отправка твита

Нач­нем с вез­десуще­го Twitter. Не очень удоб­но откры­вать при­ложе­ние или перехо­дить на сайт для того, что­бы прос­то отпра­вить твит. Поэто­му мы напишем скрипт, который будет тви­тить то, что находит­ся в буфере обме­на (не забудь уста­новить биб­лиоте­ку tweepy).

import tweepy
import clipboard
# Ключи Twitter-приложения
consumer_key = "----------"
consumer_secret = "----------"
access_key="----------"
access_secret="----------"
# Представляемся системе
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_key, access_secret)
api=tweepy.API(auth)
# Публикуем твит
text = clipboard.get()
if len(text)<=140 and len(text)>0:
api.update_status(text)

Скрипт под­клю­чает­ся к акка­унту, исполь­зуя име­ющиеся клю­чи. Их мож­но получить на офи­циаль­ном сай­те Twitter. Что­бы получить все клю­чи, нуж­но соз­дать при­ложе­ние, затем перей­ти на вклад­ку Keys and Access Tokens и нажать на кноп­ку Create my access token. Таким обра­зом мы получим четыре необ­ходимых нам клю­ча. Что­бы скрипт смог пос­тить сооб­щения, необ­ходимо дать при­ложе­нию такие пра­ва на вклад­ке Permissions.

Во всем осталь­ном фун­кци­ональ­ность край­не прос­та. Скрипт берет стро­ку из буфера обме­на, про­веря­ет, соот­ветс­тву­ет ли стро­ка фор­мату тви­та (не более 140 сим­волов), и пос­тит ее.

 

Быстрое сохранение в Instapaper

Те­перь о не менее популяр­ном сер­висе Instapaper, поз­воля­ющем сох­ранять стра­ницы для офлайн‑чте­ния. Сле­дующий трехс­троч­ный скрипт добав­ляет стра­ницу из буфера обме­на пря­мо в уста­нов­ленный на девай­се кли­ент сер­виса.

import webbrowser, clipboard
addnew='x-callback-instapaper://x-callback-url/add?url='+clipboard.get()
webbrowser.open(addnew)

Cкрипт исполь­зует так называ­емые x-callback-url — мини-API при­ложе­ний, которые мож­но вызывать через встро­енный бра­узер. На офи­циаль­ном сай­те этой фичи есть спи­сок при­ложе­ний, под­держи­вающих эту воз­можность. Струк­тура x-callback-url-зап­росов такая:

x-callback-Имя_Приложения://x-callback-url/Функция?Параметр=
 

Генератор паролей

Да, имен­но генера­тор паролей. Есть куча при­ложе­ний со схо­жей фун­кци­ональ­ностью, но мы сде­лаем свой. Прос­то потому, что хотим :).

import random, string,clipboard
pass = ''
for x in range(random.randrange(8,12)):
pass += random.choice(string.ascii_letters + string.digits)
clipboard.set(pass)

Дан­ный скрипт поможет соз­дать пароль с высокой устой­чивостью к под­бору (с вклю­чени­ем чисел и букв). Идея алго­рит­ма край­не прос­та: в пус­тую строч­ку добав­ляет­ся слу­чай­ное (от 8 до 11) чис­ло сим­волов из выше­упо­мяну­того набора. Далее пароль помеща­ется в буфер обме­на.

 

Отправка текущего местоположения на email

Иног­да про­ще нажать на кноп­ку и отпра­вить собесед­нику свой адрес, чем объ­яснить, где ты.

import smtplib, location, time
from email.mime.text import MIMEText
# SMTP-сервер
server = "адрес_сервера"
user_passwd = "пароль"
port = 22
user_name = "отправитель@мэйл"
send_name='получатель@мэйл'
# Выполняем подключение и регистрацию
s = smtplib.SMTP(server, port)
s.ehlo()
s.starttls()
s.ehlo()
s.login(user_name, user_passwd)
# Получаем координаты
location.start_updates()
time.sleep(10)
location.stop_updates()
loc = location.get_location()
addr = location.reverse_geocode(loc)[0]
# Формируем и отправляем письмо
Text = нахожусь по адресу: ' + addr['Country'] + ', город ' + addr['City']+', ' + addr['Name']
letter = MIMEText(Text,'html','utf-8')
letter['Subject']= 'Текущая геолокация'
letter['To']=send_name
letter=letter.as_string()
s.sendmail(user_name,send_name,letter)
s.close

Скрипт сос­тоит из двух час­тей: пер­вая — это работа с поч­товым сер­вером, вто­рая — получе­ние текуще­го адре­са и отправ­ка пись­ма. Оста­новим­ся на вто­рой попод­робнее. Дело в том, что фун­кции «получить текущее мес­тополо­жение» в биб­лиоте­ке location нет, но есть две фун­кции, поз­воля­ющие получить спи­сок час­то посеща­емых мест. Так как соз­дание спис­ка длит­ся все­го десять секунд (time.sleep(10)), то в нем будет все­го один объ­ект с текущим адре­сом. Этот объ­ект — сло­варь. Получим необ­ходимые зна­чения по клю­чам и занесем кра­сивую фра­зу в стро­ку Text, которую мы потом и отпра­вим.

Письмо с координатами, сгенерированное скриптом
Пись­мо с коор­дината­ми, сге­нери­рован­ное скрип­том
 

Отправка фотографии на сервер по FTP

Уже извес­тная нам биб­лиоте­ка clipboard поз­воля­ет работать не толь­ко с тек­стом, но и с изоб­ражени­ями. Это откры­вает нам новые воз­можнос­ти. Как нас­чет скрип­та, который поз­воля­ет сох­ранить фотог­рафию из буфера обме­на на FTP-сер­вер?

import ftplib, clipboard
# Получаем изображение и сохраняем в виде файла
a=clipboard.get_image()
filename='out.jpg'
a.save(filename)
# Подключаемся к серверу и заливаем картинку
con=ftplib.FTP('Host','Login','Password')
f=open(filename,'rb')
send=con.storbinary(filename,f)
con.close()

Скрипт мож­но нем­ного изме­нить, написав в пер­вых двух строч­ках

import ftplib, photos
a=photos.get_image()

Тог­да на сер­вер отпра­вит­ся не ско­пиро­ван­ная, а пос­ледняя отсня­тая фотог­рафия. А если заменить пер­вые две строч­ки на эти:

import ftplib, photos
a=photos.capture_image()

то iOS пред­ложит сде­лать фотог­рафию.

 

Работа с удаленным сервером по SSH

У мно­гих из нас есть уда­лен­ные сер­веры. У кого‑то это домаш­ний меди­апро­игры­ватель или фай­лопомой­ка, дру­гие рулят сер­верами на Amazon. Как управлять ими с iPhone или iPad? Мож­но ска­чать какой‑нибудь FTP-кли­ент, но это не вари­ант, если необ­ходимо регуляр­но выпол­нять оди­нако­вые задачи, нап­ример делать бэкап. Сти­вен Мил­лард (Stephen Millard) написал скрипт, поз­воля­ющий выпол­нять уда­лен­ные коман­ды через SSH. В упро­щен­ном виде (без про­вер­ки на пра­виль­ность вве­ден­ных дан­ных и вывод логов) он выг­лядит так:

import paramiko
import console
# Адрес, логин и имя исполняемой команды
strComputer = 'адрес'
strUser = 'логин'
strPwd = 'пароль'
strCommand = 'имя_команды'
# Подключаемся к серверу
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname=strComputer, username=strUser, password=strPwd)
# Выполняем команду
stdin, stdout, stderr = client.exec_command(strCommand)
print stdout.read()
client.close()

Для выпол­нения набора команд дос­таточ­но ско­пиро­вать строч­ку «stdin, stdout, stderr = client.exec_command(strCommand)» нес­коль­ко раз с раз­личны­ми коман­дами (либо перечис­лить все коман­ды через точ­ку с запятой. — Прим. ред.).

Работа с SSH из Pythonista
Ра­бота с SSH из Pythonista

www

  • Офи­циаль­ный форум Pythonista: goo.gl/gUkIMQ
  • До­кумен­тация по встро­енным модулям: goo.gl/Iha51A
  • Боль­шая статья о воз­можнос­тях Pythonista: goo.gl/RFtxiL
  • Сбор­ник Pythonista-скрип­тов: goo.gl/vFcYBb
 

Сокращаем ссылки при помощи goo.gl

Не­ред­ко при­ходит­ся при­бегать к сок­ращал­кам ссы­лок. Но каж­дый раз заходить на сайт, копиро­вать, встав­лять — это как‑то скуч­но. К счастью, сущес­тву­ет API goo.gl.

import googl, clipboard
client = googl.Googl("ключ")
result = client.shorten(clipboard.get())
clipboard.set(result['id'])

Cкрипт получа­ет URL из буфера обме­на, кон­верти­рует его и помеща­ет обратно в буфер. Перед запус­ком скрип­та необ­ходимо получить API Access Key. Для это­го заходим на стра­ницу API, нажима­ем Add project и в спис­ке дос­тупных сер­висов вклю­чаем URL Shortener API. Далее в левом меню выбира­ем вклад­ку APIs & auth, под­меню Credentials и жмем кноп­ку Create new Key, далее Browser Key. Пос­ле получе­ния клю­ча встав­ляем его в скрипт.

Об­рати вни­мание, что в ходе исполне­ния скрип­та перемен­ной result прис­ваивает­ся сло­варь вида {'kind': 'urlshortener#url', 'id': ShortLink', u'longUrl': 'LongLink'}. Так как нам необ­ходима толь­ко корот­кая ссыл­ка, в буфер обме­на заносит­ся зна­чение по клю­чу 'id'.

 

Очистка записной книжки

Прой­дясь по поис­ковым сис­темам, мы най­дем все­го два спо­соба очис­тки запис­ной книж­ки: уда­ление по одно­му кон­такту либо син­хро­низа­ция с пус­тым спис­ком кон­тактов на ком­пе. Нет, так неин­терес­но.

import contacts
a = contacts.get_all_people()
for i in a:
contacts.remove_person(i)
contacts.save()

Прос­то про­бега­емся по спис­ку кон­тактов. Глав­ное — не забыть сох­ранить сде­лан­ные изме­нения (пос­ледняя стро­ка).

 

Импорт друзей из ВК в записную книжку

На­конец, самый слож­ный и длин­ный скрипт — импорт номеров телефо­нов из «ВКон­такте» в запис­ную книж­ку. Как и у всех осталь­ных, у «ВКон­такте» есть API. Для питона сущес­тву­ет нес­коль­ко биб­лиотек для работы с ним. Самая извес­тная и самая прос­тая в исполь­зовании — биб­лиоте­ка со скром­ным име­нем vk.

import vk, datetime, contacts
# Функция для конвертации даты из формата ВК в формат iOS
def convertdate(date):
date = date.split('.')
if len(date) == 2:
return datetime.datetime.combine(datetime.date(1604,int(date[1]),int(date[0])),datetime.time(0, 0))
else:
return datetime.datetime.combine(datetime.date(int(date[2]),int(date[1]),int(date[0])),datetime.time(0, 0))
# Подключаемся к ВК и получаем список друзей
vkapi = vk.API('ID-приложения', 'логин', 'пароль')
a = vkapi.friends.get(fields='contacts,bdate')
a = a['items']
# Проходим по списку полученных контактов и импортируем их по одному
for i in a:
Temp = contacts.Person()
Temp.last_name= i['last_name']
Temp.first_name = i['first_name']
if 'mobile_phone' in i.keys():
try:
Temp.phone=[('mobile',i['mobile_phone'])]
except:
pass
if 'home_phone' in i.keys():
try:
Temp.phone.append(('home',i['home_phone']))
except:
pass
Temp.url = [('vk','http://vk.com/id'+str(i['id']))]
if 'bdate' in i.keys():
Temp.birthday = convertdate(i['bdate'])
contacts.add_person(Temp)
# Сохраняем контакты
contacts.save()

Как и в слу­чае с твит­тером, для скрип­та необ­ходимо соз­дать «при­ложе­ние» внут­ри «ВКон­такте». Что­бы сде­лать это, перей­ди на вклад­ку «При­ложе­ния» на сай­те VK, потом на вклад­ку «Управле­ние» и наж­ми кноп­ку «Соз­дать при­ложе­ние». На стра­нице при­ложе­ния перей­ди на вклад­ку «Нас­трой­ки» и ско­пируй «ID При­ложе­ния». Вставь «ID При­ложе­ния», «Логин» и «Пароль» в скрипт.

Раз­берем­ся, как работа­ет этот скрипт. Сна­чала мы получа­ем спи­сок дру­зей. По умол­чанию фун­кция friends.get() воз­вра­щает сло­варь, сос­тоящий из двух полей: count и items. Нас, несом­ненно, инте­ресу­ет вто­рое, но так как мы хотим получить не толь­ко име­на и фамилии, то переда­дим фун­кции параметр fields, ука­зыва­ющий на то, что мы хотим узнать. Далее мы идем по спис­ку сло­варей, где каж­дый сло­варь — это поль­зователь. При каж­дой ите­рации мы соз­даем перемен­ную Temp типа Person и по оче­реди добав­ляем в нее поля.

В про­цес­се про­хода по кон­тактам скрипт реша­ет нес­коль­ко проб­лем. Пер­вая проб­лема воз­ника­ет при экспор­те телефон­ных номеров, ведь очень час­то мы встре­чаем в ВК номера типа «кому надо — зна­ют», «сек­рет» и подоб­ные. Что­бы скрипт смог обра­ботать подоб­ные записи, не падая, исполь­зует­ся опе­ратор try. Вто­рая проб­лема воз­никла с несов­падени­ем фор­мата даты рож­дения. В получен­ном из ВК сло­варе она записа­на в виде стро­ки фор­мата DD.MM.YYYY, а в поле birthday необ­ходимо заносить дан­ные в фор­мате datetime.datetime. Для это­го и нуж­на фун­кция convertdate в начале скрип­та. Кро­ме того, дата рож­дения может быть не ука­зана вов­се.

 

Заключение

Нес­мотря на боль­шое чис­ло при­меров, мы рас­смот­рели далеко не все воз­можнос­ти Pythonista. А ведь ее фун­кци­она­ла хва­тает на очень мно­гое. Нап­ример, в App Store уже выложе­но нес­коль­ко при­ложе­ний, соз­данных в этой прог­рамме. К тому же в ско­ром вре­мени соз­датель Pythonista обе­щает выпус­тить обновле­ние с под­дер­жкой iPhone 6 и 6+ и дву­мя новыми модуля­ми для работы с напоми­нани­ями и перифе­рий­ными Bluetooth-устрой­ства­ми.

Встроенные библиотеки Pythonista

  • canvas — биб­лиоте­ка век­торной гра­фики;
  • clipboard — работа с буфером обме­на;
  • console — фун­кции, свя­зан­ные с вво­дом и выводом тек­ста;
  • contacts — дос­туп к запис­ной книж­ке;
  • editor — работа с тек­сто­вым редак­тором Pythonista;
  • keychain — дос­туп к API Keychain;
  • linguistictagger — лин­гвис­тичес­кий ана­лиз;
  • location — геоло­каци­онные сер­висы;
  • motion — сня­тие показа­ний сен­сора;
  • notification — работа с уве­дом­лени­ями;
  • photos — работа с сох­ранен­ными фотог­рафи­ями;
  • scene — 2D-гра­фика и ани­мация;
  • sound — биб­лиоте­ка зву­ков;
  • speech — кон­верта­ция тек­ста в речь;
  • ui — натив­ный GUI для iOS.
Редактор GUI
Ре­дак­тор GUI

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии