Kodomo

Пользователь

Учебная страница курса биоинформатики,
год поступления 2014

Параметры командной троки. Работа с html в python

Разбор командной строки

Когда мы вызываем программу через командную строку, мы можем также указывать ее параметры (если они есть).

Например, вспомним команду ls. Ее можно вызвать с различными параметрами.

ls -lR
ls --long --recursive
ls -l -R

Все три записи выше равнозначны между собой.

ls --sort=time # параметры могут принимать какое-то значение
ls a.txt b.txt

Если параметр написан через знак дефиса, то он называется именованным, иначе – позиционным.

В переменной sys.argv содержится список строк - все то, что было написано в командной строке (разделенное по пробелам).

Например, если мы напишем маленькую программку test_argv.py:

   1 import sys
   2 print sys.argv

И запустим ее с какими-нибудь параметрами, то получится так:

   1 $ python test_argv.py file.txt -r -w 5
   2 ['test_argv.py', 'file.txt', '-r', '-w', '5']

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

   1 import argparse
   2 parser=argparse.ArgumentParser()

parser - это так называемый объект-разборщик (далее будем называть его просто парсером).

Разберем это на примере программы сортировки (пусть будет называться sort.py).

Пусть для нее можно будет указывать три параметра:

-r --reverse
-w --word
-a --sort-alg

Для этого надо прописать:

   1 import argparse
   2 import sys
   3 parser=argparse.ArgumentParser()
   4 parser.add_argument('-w', '--word', help='word number to sort by', type=int)
   5 parser.add_argument('-r', '--reverse', action='store_true', help='reverse sort order')
   6 parser.add_argument('-a', '--sort-alg', dest='alg', help='sorting algorithm; can be "qsort" (qsort) or "merge" (merge-sort)', type=str, default='qsort')
   7 options=parser.parse_args()
   8 print(options)
   9 print(options.word)
  10 print(options.alg)# значение положилось в options.alg, как это указано в 'dest'
  11 print(options.reverse)
  12 print sys.argv

Итак, парсер будет разбирать слово, стоящее после записи '-w' ('--word'), '-a' ('--sort-alg') или '-r' ('--reverse'). Для '-w' оно должно быть целым числом, для '-a' - строкой и по умолчанию равно 'qsort'.

Фраза action='store_true' означает, что данный параметр является флагом. Если бы этого не было, то параметр нёс бы какое-то значение.

Рассмотрим диалог с командной строкой:

$ python sort.py
Namespace(alg='qsort', reverse=False, word=None)
None
qsort
False
['test1.py']
$ python sort.py --help
Usage: sort.py [options]

Options:
  -h, --help            show this help message and exit
  -w WORD, --word=WORD  word number to sort by
  -r, --reverse         reverse sort order
  -a ALG, --sort-alg=ALG
                        sorting algorithm; can be "qsort" (qsort) or "merge"
                        (merge-sort)
$ python sort.py -x
sort.py [options]
sort.py: error: unrecognized arguments: -x

Мы можем захотеть как-то реагировать на отсутствие значения для обязательного параметра (например, параметра '-w'):

   1 import argparse
   2 import sys
   3 parser=argparse.ArgumentParser()
   4 parser.add_argument('-w', '--word', help='word number to sort by', type=int)
   5 parser.add_argument('-r', '--reverse', action='store_true', help='reverse sort order')
   6 parser.add_argument('-a', '--sort-alg', dest='alg', help='sorting algorithm; can be "qsort" (qsort) or "merge" (merge-sort)', type=str, default='qsort')
   7 options=parser.parse_args()
   8 print(options.word)
   9 if not options.word:
  10     parser.error('Word number is not given')

Тогда диалог с командной строкой будет выглядеть так:

$ python sort.py
None
Usage: sort.py [options]

sort.py: error: Word number is not given

$ python sort.py -w 3
3

Работа с html в python

При работе бывает необходимо извлекать информацию из html страниц. Модули стандартной библиотеки питона для открытия web-документов - urllib2, urllib. Работа с html документами аналогична работе с файлами. Базовые операции - открытие, чтение и закрытие документа.

   1 import urllib2
   2 html_filelike_object = urllib2.urlopen("http://www.genboree.org/EdaccData/Current-Release/study-sample-experiment/UW/Fetal_Lung/Expression_Array/")
   3 html = html_filelike_object.read()
   4 html_filelike_object.close()

Открытие url осуществляется методом urlopen(), метод возвращает информацию о странице, представленную в обьекте аналогичном файловому. Чтение - методами read() (в одну строку) и readlines()(в список строк). Также как при работе с файлами необходимо закрытие html-документа. Прочитанная веб-страница представляет собой html текст - набор элементов, заключенных в тэги(открывающие(<html>, <head>, <a>) и закрывающие </html>, </head>… ). Некоторые элементы также имеют различные дополнительные атрибуты, которые указываются в открывающем тэге элемента.

   1 <tag attribute1="value1" attribute2="value2" >

Для работы с информацией внутри тэгов можно использовать классы-разборщики. Вообще, существует большое количество библиотек для удобного разбора подобных документов (lxml, Beautiful Soup). Стандартная библиотека python для работы с такими документами - HTMLParser (html.parser в Python 3). В модуле HTMLParser определяется класс HTMLParser. Этот класс включает стандартные методы, которые обрабатывают ситуации встречи открывающих тэгов, данных элемента, закрывающих тэгов, комментариев и тд. Чтобы описать те операции, которые должны совершаться программой в каком либо из этих случаев(встрече открывающего тэга) пользователь должен определить собственный подкласс, наследующий от класса HTMLParser, и описать в нем работу соответствующих методов - handle_starttag(tag, attrs), handle_endtag(tag), handle_data(data). Таким образом, мы можем описывать действия, которые нужно выполнить при встрече открывающего тэга, закрывающего тэга и при разборе содержимого между этими тэгами.

   1 from html.parser import HTMLParser
   2 
   3 class MyHTMLParser(HTMLParser):
   4     def handle_starttag(self, tag, attrs):
   5         print("Encountered a start tag:", tag)
   6     def handle_endtag(self, tag):
   7         print("Encountered an end tag :", tag)
   8     def handle_data(self, data):
   9         print("Encountered some data  :", data)

В метод handle_starttag() передается два аргумента - имя тэга, и список атрибутов элемента, представленных в виде списка кортежей пар (имя_атрибута, значение). Методы handle_endtag() и handle_data работают с именами тэгов. Т.е., можно задать действия в случае встречи закрывающего тэга с определенным названием. Другие полезные методы класса HTMLParser – getpos() и get_starttag_text(), они возвращают соответственно номер обрабатываемой строки и имя предыдущего последнего открытого тэга.

После описания действий нашего разборщика создается элемент заданного класса. В методе feed()объекту класса передается разбираемый html-документ. В конце необходимо закрытие обработки html - вызов метода close().

   1 parser = MyHTMLParser()
   2 parser.feed(‘html’)
   3 parser.close()

Пример 1. Записываем данные из таблицы html:

   1 h = '''<body><table><tr><td>Cell 1</td><td>Cell 2</td></tr><tr><td>Cell 3</td><td>Cell 4</td></tr></table></body>'''
   2 
   3 class MyParser(HTMLParser):
   4     #def __init__(self):
   5     def reset(self):
   6         HTMLParser.reset(self)
   7         #HTMLParser.__init__(self)
   8         self.table_content = []
   9         self.table_row = []
  10 
  11 
  12     def handle_endtag(self,tag):
  13         if tag == "tr":
  14             self.table_content.append(self.table_row)
  15             self.table_row = []
  16 
  17     def handle_data(self, data):
  18         if self.get_starttag_text() == "<td>":
  19             self.table_row.append(data)
  20 
  21 p=MyParser()
  22 p.feed(h)
  23 p.close()
  24 
  25 
  26 >>> p.table_content
  27 [['Cell 1', 'Cell 2'], ['Cell 3', 'Cell 4']]

Обратите внимание, что вместо вызова init класса может быть более корректным вызвать собственный метод класса HTMLParser - reset().

Если url представляет собой путь к файлу, его содержимое можно сохранить в файл на компьютере.

   1 url='file.gz'
   2 u = urllib2.urlopen(url)
   3 f = open(file_name, 'wb')
   4 f.write(u.read())
   5 f.close()
   6 u.close()

В модуле urllib также есть метод urlretrive(), принимающий в качестве параметров url и имя записываемого файла, также в качестве параметра можно передать функцию, которая будет вызвана в начале записи и через определенные промежутки записи блоков некоторого размера в выходной файл. Функция должна принимать три параметра - количество прочитанных блоков, размер блока, размер файла. Прописывание этой функции позволяет отслеживать прогресс закачки файла.

   1 urllib.urlretrieve(url, 'local_file_name', reporthook=some_progress_bar_function)

Еще когда нам может понадобиться работа с web – это отправка поисковых запросов, а также заполнение форм. Пример, демонстрирующий работу метода Request() модуля urllib2:

   1 import urllib
   2 import urllib2
   3 
   4 url = 'http://www.someurl’
   5 
   6 values = {'name' : 'Michael’,
   7           'location' : 'Russia'}
   8 
   9 data = urllib.urlencode(values)
  10 req = urllib2.Request(url, data)
  11 response = urllib2.urlopen(req)
  12 the_page = response.read()

Метод отправляет данные поля формы, затем можно получить результат отправленного запроса.