Enigma2 plugin to dowload and create channels picons files form lyngsat.com

get_picons.py 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. # coding: utf-8
  2. #
  3. # This file is part of GetPicons - enigma2 plugin to download picons from lyngsat.com
  4. # Copyright (c) 2016 ivars777 (ivars777@gmail.com)
  5. # Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
  6. """
  7. Dowload and create Enigma2 channels' picons files form lyngsat.com
  8. Usage [options]
  9. Options:
  10. -p PACKAGE_LIST, --package=PACKAGE_LIST list of package names (html file name in lyngsat),
  11. e.g "viasat,ntvplus36"
  12. -s SAT_LIST, --sat=SAT_LIST list of sattelite positions, e.g. "4.9,-0.8"
  13. -z SIZE icon size, e.g. "100x60", default - "220x132"
  14. -f PATH, --folder PATH picon files output folder, default - "/media/hdd/picon"
  15. -e PATH, --enigma PATH enigma2 folder whera lamedb,settings are located, default - "/etc/enigma2"
  16. you can use urls, e.g. "ftp://root@receiver_address/etc/enigma2"
  17. -b COLOR_CODE, --background=COLOR_CODE background color code in hex format(HHHHHHHHH), last pair - opacity level
  18. default - FFFFFF20 (almost transparent white)
  19. -l, --simple simple, low resolution image with white background
  20. -o, --overwrite overwrite existing picons file (default - no)
  21. -d, --debug display work progress and write debug info to file for not found services
  22. -h, --help this help file
  23. (c)Ivars777 (ivars777@gmail.com) 2013-2015, v0.2
  24. """
  25. import sys, os, os.path, getopt, traceback
  26. import re
  27. import urllib2
  28. import requests
  29. try:
  30. from PIL import Image
  31. except:
  32. import Image
  33. from StringIO import StringIO
  34. import logging
  35. options = args = None
  36. _sd= lambda x,d: d if x is None else x # set default value
  37. _sl= lambda x: False if x is None else True # set True of False for option
  38. hex2rgb = lambda c: tuple(int(c[i:i+2], 16) for i in xrange(0,len(c),2))
  39. def parse_arguments(argv,opt_short,opt_long):
  40. "Parse command line arguments"
  41. try:
  42. options, args = getopt.gnu_getopt(argv, opt_short,opt_long)
  43. options = Rec(dict([(o[0].replace("-",""),o[1]) for o in options]))
  44. except getopt.GetoptError, err:
  45. print err.msg
  46. print __doc__
  47. sys.exit(2)
  48. if options.has_key("h") or options.has_key("help"):
  49. print __doc__
  50. sys.exit(2)
  51. return options,args
  52. services = None
  53. def main(argv):
  54. global options, args, services
  55. # Parsing options
  56. opt_short = 'p:s:z:f:e:b:lodh'
  57. opt_long = ["package=","sat=","size=","folder=","enigma=","background=","simple","overwrite","debug","help"]
  58. options,args = parse_arguments(argv[1:], opt_short, opt_long)
  59. options.package = _sd(options.package,_sd(options.p,""))
  60. options.sat = _sd(options.sat,_sd(options.s,""))
  61. options.enigma = _sd(options.enigma,_sd(options.e,"/etc/enigma2"))
  62. options.folder = _sd(options.folder,_sd(options.f,"/media/hdd/picon"))
  63. options.size = _sd(options.size,_sd(options.z,"220x132"))
  64. options.simple = _sl(_sd(options.simple, options.l))
  65. options.background = _sd(options.background, _sd(options.b, "FFFFFFFF"))
  66. options.overwrite = _sl(_sd(options.overwrite,options.o))
  67. options.debug = _sl(_sd(options.debug,options.d))
  68. options.w,options.h = map(int,options.size.split("x"))
  69. options.background = hex2rgb(options.background.lstrip("#"))
  70. if not os.path.exists(options.folder):
  71. os.makedirs(options.folder)
  72. if options.debug:
  73. #filename="get_picons.log" if not os.name == "posix" else "/var/log/get_picons.log"
  74. filename = os.path.join(options.folder,"get_picons.log")
  75. FORMAT = "%(asctime)-15s %(message)s"
  76. logging.basicConfig(filename=filename, format=FORMAT,level=logging.ERROR)
  77. print "** Analyzing lamedb"
  78. services = DBServices(options.enigma)
  79. if options.sat:
  80. package_list = []
  81. for sat in options.sat.split(","):
  82. package_list.extend(get_packages(sat))
  83. elif options.package:
  84. package_list = options.package.split(",")
  85. else: # get sattelite list from Enigma settings
  86. sat_list = []
  87. package_list = []
  88. if not "ftp:" in options.enigma:
  89. fname = os.path.join(options.enigma,"settings")
  90. f = open(fname)
  91. else:
  92. sep = "" if options.enigma[-1]=="//" else "//"
  93. fname = options.enigma + sep + "settings"
  94. f = urllib2.urlopen(fname)
  95. for line in f:
  96. if not "config.Nims.0.advanced.sat." in line: continue
  97. sat_list.append(line.split(".")[5])
  98. for sat in sat_list:
  99. package_list.extend(get_packages(sat))
  100. for package in package_list:
  101. create_picons(package)
  102. def create_picons(package):
  103. "Create picons files for package"
  104. global services,options
  105. url_package = "https://www.lyngsat.com/packages/%s.html"%package
  106. if options.debug:
  107. print "** Downloading and looking %s for picons"%url_package
  108. num_picons = 0
  109. num_skipped = 0
  110. num = 0
  111. try:
  112. #soup = html = urllib2.urlopen(url_package).read().decode("latin1")
  113. soup = html = get_page(url_package).decode("latin1")
  114. except:
  115. raise Exception("Package page '%s' does not found"%url_package)
  116. title = re.search("<title>(.+?)</title>", soup, re.DOTALL | re.IGNORECASE).group(1)
  117. pos = re.search("\d+\.\d+",title).group().replace(".","")
  118. ew = re.search("\xb0.",title).group()[1]
  119. ns = int(pos)
  120. if ew == "W":
  121. ns = 3600 - ns
  122. if ns==48: ns=49
  123. if ns==359: ns=360
  124. #pos = "%04x0000"%ns
  125. #pos_num = int(pos[0:4],16)
  126. title2 = title[0:title.index("- LyngSat")]
  127. print "** %s: "%title2.replace(u'\xb0',""),
  128. tables = re.findall(r"<table width=720 border cellspacing=0 cellpadding=0>\s*(?:(?=<tr>))(.+?)</table>", soup, re.DOTALL | re.IGNORECASE)
  129. for table in tables:
  130. tr= html_findall("tr",table)
  131. for i in range(2,len(tr)-1):
  132. td= html_findall("td",tr[i])
  133. if len(td) == 10:
  134. freq,polar = re.search(r"<b>(\d+) ([HVLR])", tr[i], re.DOTALL | re.IGNORECASE).groups()
  135. freq = int(freq)
  136. p_value = {"H":0,"V":1,"L":2,"R":3}
  137. polar = p_value[polar]
  138. b=1
  139. else:
  140. b=0
  141. icon_url = html_attr("src",td[b])
  142. if icon_url:
  143. # https://www.lyngsat.com/logo/tv/vv/viasat_history.png
  144. # https://www.lyngsat-logo.com/hires/vv/viasat_history.png
  145. icon_url_hr = "https://www.lyngsat-logo.com" + icon_url.group(1).replace("/logo/tv", "/hires")
  146. icon_url_lr = "https://www.lyngsat.com" + icon_url.group(1)
  147. else:
  148. icon_url = ""
  149. name = html_text(td[b+1]).group(1)
  150. sid = html_text(td[b+5])
  151. sid = sid.group(1).replace("&nbsp;","") if sid else ""
  152. sid = int(sid) if sid and not sid == u"-" else ""
  153. vpid = html_text(td[b+6])
  154. vpid = vpid.group(1).replace("&nbsp;","") if vpid else ""
  155. #try:
  156. # vpid = int(vpid)
  157. #except Exception:
  158. # vpid = None
  159. #vpid = int(vpid) if vpid and not vpid == u"-" else None
  160. if not sid or not vpid or icon_url=="":
  161. continue
  162. if options.debug:
  163. print " package:%i/%s: service:%s "%(ns,package, name.encode("ascii","replace")),
  164. num += 1
  165. sref = find_sref(ns,freq,polar,sid)
  166. if not sref:
  167. sref = find_sref(ns,freq+1,polar,sid)
  168. if not sref:
  169. sref = find_sref(ns,freq-1,polar,sid)
  170. if not sref:
  171. sref = find_sref(ns, freq, polar-2, sid)
  172. if not sref:
  173. if options.debug:
  174. print " -- NOK (no sref in lamedb!)"
  175. logging.error(u" no sref - package:%i/%s: service:%s pos:%s/%s freq:%i polar:%s sid:%i/%x"%(ns,package, name,ns, pos_int2str(ns),freq,polar,sid,sid))
  176. continue
  177. fname = sref.replace(":","_")
  178. fname = fname[:-1]+".png"
  179. fname = os.path.join(options.folder, fname)
  180. if os.path.exists(fname) and not options.overwrite:
  181. if options.debug: print " -- skipped"
  182. num_skipped += 1
  183. continue
  184. if options.simple:
  185. data = get_page(icon_url_lr)
  186. hires = False
  187. else:
  188. data = get_page(icon_url_hr)
  189. hires = True
  190. if not data: # in not hires image available use lowres image
  191. data = get_page(icon_url_lr)
  192. hires = False
  193. if not data:
  194. if options.debug: print " -- NOK (no picon image)"
  195. continue
  196. try:
  197. im = Image.open(StringIO(data))
  198. im.thumbnail((options.w,options.h), Image.ANTIALIAS)
  199. if hires:
  200. im2 = Image.new("RGBA",(options.w,options.h),options.background)
  201. #im2 = Image.new("RGBA",(options.w,options.h),(255,255,255,128))
  202. width, height = im.size
  203. x0 = (options.w-width)/2
  204. y0 = (options.h-height)/2
  205. if im.mode <> "RGBA":
  206. im = im.convert("RGBA")
  207. im2.paste(im,(x0,y0),im)
  208. else:
  209. im2 = im
  210. #im2 = im2.convert('P', palette=Image.ADAPTIVE)
  211. except Exception as e:
  212. print e.message
  213. traceback.print_exc()
  214. im2 = None
  215. if not im2:
  216. if options.debug: print " -- NOK (no picon image)"
  217. continue
  218. if options.debug: print " -- downloaded"
  219. im2.save(fname,"png")
  220. del im2,im
  221. num_picons += 1
  222. print "%i picons created, %i skipped"%(num_picons,num_skipped)
  223. def get_packages(sat):
  224. "Get packages list (names) for sattelite from lyngsat.com page"
  225. global options
  226. sat= sat.replace(".","")
  227. num = int(sat)
  228. if num>1800: num = num - 3600
  229. if num>0 and num<730: soup = get_soup("europe")
  230. elif num>730 and num<1600: soup = get_soup("asia")
  231. elif num<0 and num>-610: soup = get_soup("atlantic")
  232. elif num<-610 and num>-1600: soup = get_soup("america")
  233. else:
  234. return []
  235. i1,i2 = gr=re.search(r"<table cellspacing=0 border>\s*(?:(?=<tr>))(.+?)</table>", soup, re.DOTALL | re.IGNORECASE).span()
  236. packages = []
  237. for s in re.findall("<tr>(.+?)</tr>", soup[i1:i2], re.DOTALL | re.IGNORECASE):
  238. gr = re.search(r"(\d+.)</font><font size=1>(\d).+#176;([EW])", s,re.DOTALL | re.IGNORECASE).groups()
  239. pos = int("".join(gr[:-1]).replace(".",""))
  240. if gr[2] == "W": pos = -pos
  241. if abs(num - pos) <=2:
  242. package = re.search(r"www\.lyngsat\.com/packages/(\w.+?)\.html", s, re.DOTALL | re.IGNORECASE).group(1)
  243. packages.append(package)
  244. return packages
  245. soups = {}
  246. def get_soup(region):
  247. if soups.has_key(region):
  248. return soups[region]
  249. url = "http://www.lyngsat.com/packages/%s.html"%region
  250. if options.debug:
  251. print "** Downloading and looking %s for packages"%url
  252. try:
  253. #html = urllib2.urlopen(url).read().decode("latin1")
  254. html = get_page(url).decode("latin1")
  255. except:
  256. raise Exception("Packege page '%s' does not found"%url)
  257. soups[region] = html
  258. return soups[region]
  259. def find_sref(ns,freq,polar,sid):
  260. "Find service reference according to given parameters"
  261. global services
  262. tp = services.get_transp_by_pic((ns,freq,polar))
  263. if tp:
  264. serv = services.get_service_by_chid((sid,tp["tsid"],tp["onid"]))
  265. if serv:
  266. return serv["sref"]
  267. class DBServices(object):
  268. """Dreambox services, stored in lamedb (E2)/services(E1) file handling class"""
  269. def __init__(self,service_path,enigma=2):
  270. self.enigma = enigma
  271. self.service_path = service_path
  272. if self.enigma == 2:
  273. if not "ftp:" in service_path:
  274. self.service_fname= os.path.join(service_path,"lamedb")
  275. self.bouquets_fname = os.path.join(service_path, "bouquets.tv")
  276. else:
  277. sep = "" if service_path[-1]=="//" else "//"
  278. self.service_fname= service_path+sep+"lamedb"
  279. self.bouquets_fname = service_path+sep+"bouquets.tv"
  280. else: # ENIGMA === "1":
  281. self.service_fname = os.path.join(service_path,"services")
  282. self.bouquets_fname = os.path.join(service_path, "userbouquets.tv.epl")
  283. self.services = []
  284. self.index_sref= {}
  285. self.index_chid = {}
  286. self.index_name = {}
  287. self.index_provider = {}
  288. self.bouquets = []
  289. self.bouquets_services = {}
  290. self.transp = []
  291. self.tp_index_tpid = {}
  292. self.tp_index_pic ={}
  293. self._load_services()
  294. #self._load_bouquets()
  295. def _load_services(self):
  296. #tpref - lamedb/transponders
  297. # NS:TSID:ONID
  298. # s FREQ:SR:POLAR:FREC:49:2:0
  299. # X X X
  300. # D D D D
  301. # lref - lamedb/services
  302. # SID:NS:TSID:ONID:STYPE:UNUSED(channelnumber in enigma1)
  303. # 0 1 2 3 4 5
  304. # X X X X D D
  305. # wref bouquets/picon
  306. # REFTYPE:FLAGS:STYPE:SID:TSID:ONID:NS:PARENT_SID:PARENT_TSID:UNUSED
  307. # 0 1 2 3 4 5 6 7 8 9
  308. # D D X X X X X X X X
  309. f_services = open(self.service_fname,"r") if not self.service_fname[0:4] == "ftp:" else urllib2.urlopen(self.service_fname)
  310. line = f_services.readline()
  311. if not "eDVB services" in line:
  312. raise Exception("no correct lamedb file")
  313. line = f_services.readline()
  314. # Read transponders
  315. i = 0
  316. while True:
  317. line = f_services.readline()
  318. if "end" in line: break
  319. #tp = record.Rec()
  320. tp = {}
  321. ff = line.strip().split(":")
  322. tp["ns"] = ns = pos_str2int(ff[0])
  323. tp["tsid"] = tsid = int(ff[1],16)
  324. tp["onid"] = onid = int(ff[2],16)
  325. line = f_services.readline()
  326. tp["params"] = params = line.strip().split(" ")[1]
  327. ff = params.split(":")
  328. tp["freq"] = freq = int(ff[0][:-3])
  329. tp["polar"] = polar = int(ff[2])
  330. tp["tpid"] = tpid = (ns,tsid,onid)
  331. self.transp.append(tp)
  332. self.tp_index_tpid[tpid] = i
  333. self.tp_index_pic[(ns,freq,polar)] = i
  334. line = f_services.readline()
  335. i += 1
  336. # Reading services
  337. i= 0
  338. line = f_services.readline()
  339. while True:
  340. line = f_services.readline()
  341. if line[0:3] == "end": break
  342. if not line: break
  343. #rec = record.Rec()
  344. rec = {}
  345. rec["lref"] = line.lower().strip().decode("utf-8")
  346. line = f_services.readline()
  347. #line = line.replace('\xc2\x87', '').replace('\xc2\x86', '')
  348. #line = decode_charset(line)
  349. line = line.decode("utf-8")
  350. rec["name"] = line.strip()
  351. line = f_services.readline()
  352. pl = line.split(",")
  353. provider = ""
  354. for p in pl:
  355. if p[0:2] == "p:":
  356. provider = p[2:].strip()
  357. break
  358. if provider == "":
  359. provider = "unknown"
  360. rec["provider"] = provider.decode("utf-8")
  361. rec["sref"] = lref2sref(rec["lref"])
  362. r = lref_parse(rec["lref"])
  363. rec["stype"] = r["stype"]
  364. rec["chid"] = (r["sid"],r["tsid"],r["onid"])
  365. self.services.append(rec)
  366. self.index_sref[rec["sref"]] = i
  367. self.index_chid[rec["chid"]] = i
  368. name = rec["name"].lower()
  369. if not self.index_name.has_key(name): self.index_name[name] = []
  370. self.index_name[name].append(i)
  371. provider = rec["provider"].lower()
  372. if not self.index_provider.has_key(provider): self.index_provider[provider] = []
  373. self.index_provider[provider].append(i)
  374. i += 1
  375. f_services.close()
  376. def _load_bouquets(self):
  377. f_bouquets = open(self.bouquets_fname,"r") if not self.bouquets_fname[0:4] == "ftp:" else urllib2.urlopen(self.bouquets_fname)
  378. for line in f_bouquets.readlines():
  379. if line[0:9] == "#SERVICE:":
  380. if self.enigma==1:
  381. bn = line.strip().split("/")
  382. else:
  383. bn = line.strip().split(":")
  384. bfn = bn[-1]
  385. bf = open(os.path.join(self.service_path,bfn))
  386. for line2 in bf.readlines():
  387. if line2[0:5] == "#NAME":
  388. bname = line2.strip()[6:]
  389. self.bouquets.append(bname)
  390. self.bouquets_services[bname] = []
  391. elif line2[0:8] == "#SERVICE":
  392. sref = line2.strip()[9:]
  393. r = sref_parse(sref)
  394. if r["flags"] == 64: continue
  395. self.bouquets_services[bname].append(sref)
  396. bf.close()
  397. f_bouquets.close()
  398. def get_bouquets(self):
  399. if not self.bouquets:
  400. self._load_bouquets()
  401. return self.bouquets
  402. def get_bouquet_services(self,bn):
  403. if not self.bouquets:
  404. self._load_bouquets()
  405. return [self.get_service_by_sref(sref) for sref in self.bouquets_services[bn]]
  406. def get_service_by_sref(self,sref):
  407. return self.services[self.index_sref[sref]] if self.index_sref.has_key(sref) else None
  408. def get_service_by_chid(self,chid):
  409. return self.services[self.index_chid[chid]] if self.index_chid.has_key(chid) else None
  410. def get_service_by_name(self,name):
  411. return [self.services[i] for i in self.index_name[name]]
  412. def get_service_by_provider(self,provider):
  413. return [self.services[i] for i in self.index_provider[provider]]
  414. def get_transp_by_tpid(self,tpid):
  415. return self.transp[self.tp_index_tpid[tpid]] if self.tp_index_tpid.has_key(tpid) else None
  416. def get_transp_by_pic(self,picid):
  417. return self.transp[self.tp_index_pic[picid]] if self.tp_index_pic.has_key(picid) else None
  418. def decode_charset(s):
  419. u = None
  420. if isinstance(s,unicode):
  421. return s
  422. charset_list=('iso-8859-4','iso-8859-1','iso-8859-2''iso-8859-15')
  423. for charset in charset_list:
  424. try:
  425. u=unicode(s,charset,"strict")
  426. except:
  427. pass
  428. else:
  429. break
  430. if u == None:
  431. raise Error, "CHARSET ERROR while decoding lamedb. Aborting !"
  432. else:
  433. return(u)
  434. # lref - lamedb/services
  435. # SID:NS:TSID:ONID:STYPE:UNUSED(channelnumber in enigma1)
  436. # 0 1 2 3 4 5
  437. # X X X X D D
  438. #
  439. # wref bouquets/picon
  440. # REFTYPE:FLAGS:STYPE:SID:TSID:ONID:NS:PARENT_SID:PARENT_TSID:UNUSED
  441. # 0 1 2 3 4 5 6 7 8 9
  442. # D D X X X X X X X X
  443. def lref2sref(s):
  444. "Converts service refefence from lamedb format to bouquets/picon (standard) format"
  445. f = s.split(":")
  446. sid = int(f[0],16)
  447. ns = int(f[1], 16)
  448. tsid = int(f[2],16)
  449. onid = int(f[3],16)
  450. stype = int(f[4])
  451. s2 = "1:0:%X:%X:%X:%X:%X:0:0:0:" % (stype,sid,tsid,onid,ns)
  452. return s2
  453. def lref_parse(s):
  454. "Parse lamedb/service string, return dictionary of items"
  455. f = s.split(":")
  456. r = {}
  457. r["sid"] = int(f[0],16)
  458. r["ns"] = int(f[1], 16)
  459. r["tsid"] = int(f[2],16)
  460. r["onid"] = int(f[3],16)
  461. r["stype"] = int(f[4])
  462. return r
  463. def sref2lref(s):
  464. "Converts service refefence from bouquets/picon (standard) format to lamedb format"
  465. f = s.split(":")
  466. reftype = int(f[0])
  467. flags = int(f[1])
  468. stype = int(f[2],16)
  469. sid = int(f[3],16)
  470. tsid = int(f[4],16)
  471. onid = int(f[5],16)
  472. ns = int(f[6],16)
  473. s2 = "%04x:%08x:%04x:%04x:%i:0" % (sid,ns,tsid,onid,stype)
  474. return s2
  475. def sref_parse(s):
  476. "Parse service refefence string , return dictionary of items"
  477. f = s.split(":")
  478. r = {}
  479. r["reftype"] = int(f[0])
  480. r["flags"] = int(f[1])
  481. r["stype"] = int(f[2],16)
  482. r["sid"] = int(f[3],16)
  483. r["tsid"] = int(f[4],16)
  484. r["onid"] = int(f[5],16)
  485. r["ns"] = int(f[6],16)
  486. return r
  487. pos_int2str = lambda pos_num: "%04x0000"%pos_num
  488. pos_str2int = lambda pos: int(pos[0:4],16)
  489. def decode_charset(s):
  490. u = None
  491. charset_list = ('utf-8','iso-8859-1','iso-8859-2','iso-8859-15')
  492. for charset in charset_list:
  493. try:
  494. u = unicode(s,charset,"strict")
  495. except:
  496. pass
  497. else:
  498. break
  499. if u == None:
  500. print("CHARSET ERROR while decoding string")
  501. sys.exit(1)
  502. else:
  503. return(u)
  504. headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
  505. headers = headers2dict("""
  506. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
  507. Referer: http://www.lyngsat.com/
  508. """)
  509. def get_page(url):
  510. r=requests.get(url,headers=headers)
  511. if r.status_code in (200,304):
  512. return r.content
  513. else:
  514. return ""
  515. html_text = lambda html: re.search(r">([^<^\n]+?)<", html, re.DOTALL | re.IGNORECASE)
  516. html_tag = lambda tag, html: re.search(r"<%s\b[^>]*>(.*?)</%s>"%(tag,tag), html, re.DOTALL | re.IGNORECASE)
  517. html_attr = lambda attr,html: re.search("""%s="?([^'" >]+)"""%(attr), html, re.DOTALL | re.IGNORECASE)
  518. html_findall_content = lambda tag,html: re.findall(r"<%s\b[^>]*>(.*?)</%s>"%(tag,tag), html, re.DOTALL | re.IGNORECASE)
  519. html_findall = lambda tag,html: re.findall(r"<%s\b[^>]*>.*?</%s>"%(tag,tag), html, re.DOTALL | re.IGNORECASE)
  520. import UserDict
  521. class Rec(UserDict.DictMixin):
  522. "Dict like class allowing a.x instead of a['x']"
  523. def __init__(self, dict=None, **kwargs):
  524. self.__dict__ = {}
  525. if dict is not None:
  526. self.update(dict)
  527. if len(kwargs):
  528. self.update(kwargs)
  529. def __setitem__(self, name, value): setattr(self, name, value)
  530. def __getitem__(self, name): return getattr(self,name,None)
  531. def __getattr__(self,key): return None
  532. def has_key(self,key): return True if self.__dict__.has_key(key) else False
  533. def keys(self): return list(self.__dict__)
  534. if __name__ == "__main__":
  535. #print "** Starting..."
  536. sys.exit(main(sys.argv))