2014-09-19 3 views
-1

У меня есть проект, над которым я работаю дома, который использует API rottentomatoes для сбора фильмов в настоящее время в кинотеатрах. Затем он собирает все изображения на странице imdb этих фильмов. Проблема, с которой я столкнулся, - это сбор изображений. Цель здесь заключается в том, чтобы заставить этот код работать под 8 секундами, но команда regex и я запускаю навсегда! В настоящее время я использую регулярное выражение:Разбор больших кусков HTML с re.findall()

re.findall('<img.*?>', str(line)) 

где линия кусок HTML

Кто-нибудь есть более регулярное выражение, что они могут думать о всех комментариях приветственных !! (возможно, более утонченный?)

Полный код ниже и прилагается.

import json, re, pprint, time 
from urllib2 import urlopen 

def get_image(url): 

    total = 0 
    page = urlopen(url).readlines() 

    for line in page: 

     hit = re.findall('<img.*?>', str(line)) 
     total += len(hit) 
    # print('{0} Images total: {1}'.format(url, total)) 
    return total 


if __name__ == "__main__": 
    start = time.time() 
    json_list = list() 
    url = "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json?apikey=<apikey>" 
    response = urlopen(url) 
    data = json.loads(response.read()) 

    for i in data["movies"]: 
     json_dict = dict() 
     json_dict["Title"] = str(i['title']) 
     json_dict["url"] = str("http://www.imdb.com/title/tt" + i['alternate_ids']['imdb']) 
     json_dict["imdb_id"] = str(i['alternate_ids']['imdb']) 
     json_dict["count"] = get_image(str(json_dict["url"])) 
     json_list.append(json_dict) 
    end = time.time() 
    pprint.pprint(json_list) 
    runtime = end - start 
    print "Program runtime: " + str(runtime) 
+1

Рассматривали ли вы с помощью BeautifulSoup? – hwnd

+4

[* sigh *] (http://stackoverflow.com/a/1732454/2581969) – roippi

+0

Я хотел бы запустить его с помощью python2.7 std libs. Нет внешних зависимостей. –

ответ

0

Although I know using regex to search for img tags in HTML is not ideal, here is the approached I ended up going with. By threading I was able to get the runtime to anywhere from 2-12 seconds depending on your connection:

#No shebang line, please run in Linux shell % python img_count.py 

#Python libs 
import threading, urllib2, re 
import Queue, json, time, pprint 

#Global lists 
JSON_LIST = list() 
URLS = list() 

def get_movies(): 
    url = "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json?apikey= <apikey>" 
    response = urllib2.urlopen(url) 
    data = json.loads(response.read())  
    return data 


def get_imgs(html): 
    total = 0 
    # This next line is not ideal. Would much rather use a lib such as Beautiful Soup for this 
    total += len(re.findall(r"<img[^>]*>", html)) 
    return total 


def read_url(url, queue): 
    data = urllib2.urlopen(url).read() 
    queue.put(data) 


def fetch_urls(): 
    result = Queue.Queue() 
    threads = [threading.Thread(target=read_url, args = (url,result)) for url in URLS] 
    for thread in threads: 
     thread.start() 
    for thread in threads: 
     thread.join() 
    return result 


if __name__ == "__main__": 
    start = time.time() 
    movies = get_movies() 
    for movie in movies["movies"]: 
     url = "http://www.imdb.com/title/tt" + movie['alternate_ids']['imdb'] 
     URLS.append(url)  
    queue = fetch_urls() 
    while movies["movies"]: 
     movie = movies["movies"].pop() 
     job = queue.get() 
     total = get_imgs(job)  
     json_dict = { 
       "title": movie['title'], 
       "url": "http://www.imdb.com/title/tt" + movie['alternate_ids']['imdb'], 
       "imdb_id": movie['alternate_ids']['imdb'], 
       "count": total 
       } 
     JSON_LIST.append(json_dict)  
    pprint.pprint(JSON_LIST) 
    end = time.time() 
    print "\n" 
    print "Elapsed Time (seconds):", end - start 
1

Вы не можете разобрать HTML с регулярными выражениями. Если вы можете использовать только стандартные библиотеки для Python 2, использовать HTMLparser:

from HTMLParser import HTMLParser 
class ImgFinder(HTMLParser): 
    def handle_starttag(self, tag, attrs): 
     if tag == 'img': 
      print 'found img tag, src=', dict(attrs)['src'] 

parser = ImgFinder() 
parser.feed(... HTML source ...) 
+0

Пробовал это уже .... Это не находит вложенные теги img .... а как насчет тегов img, сгенерированных javascript? Нет. –

+0

@DirkDigler * no * parsing schema сможет анализировать теги img, созданные javascript, потому что они просто не находятся в источнике страницы. Они существуют только в DOM, когда движок javascript запускает все сценарии, которые нужно запустить. – roippi

+0

@roippi Javascript МОЖЕТ быть в источнике страницы .... Запустите этот код и сообщите мне, если вы видите Javascript в stdout: page = urlopen («http://www.imdb.com/title/tt2978462») .readlines() для строки на странице: if line: print line –

1

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

Сравните эти две:

>>> timeit('import re; re.findall("<img.*?>", \'blah blah blah <img src="http://www.example.org/test.jpg"> blah blah blah <img src="http://wwww.example.org/test2.jpg"> blah blah blah\')') 
3.366645097732544 
>>> timeit('import re; re.findall("<img[^>]*>", \'blah blah blah <img src="http://www.example.org/test.jpg"> blah blah blah <img src="http://wwww.example.org/test2.jpg"> blah blah blah\')') 
2.328295946121216 

Вы можете видеть, что последнее регулярное выражение, которое эквивалентно, на самом деле заметно быстрее. Это потому, что он не требует возврата. Смотрите это замечательное сообщение в блоге http://blog.stevenlevithan.com/archives/greedy-lazy-performance для объяснения, почему это так.

+0

I think '.*?>» - это повторяющийся двухэтапный процесс. Проверяем, является ли символ '>', если нет, то потребляем 1 символ (повторяется снова и снова). '[^>] *' немедленно найти следующий '>', а затем использовать совпадение позиции здесь. Но его можно воспроизвести, чтобы сделать его отступником от '>', если следующий символ не '' '.Это полезно, если вам нужно искать назад от начальной точки, где все накладывается, и никакие реальные жесткие якоря не могут быть использованы. – sln

+0

Спасибо FatalError: "] *>" Сбрито несколько секунд от времени выполнения. И да, я согласен с вами в том, что регулярное выражение - это неправильный способ, но я хочу, чтобы это закончилось с помощью python 2.x, поэтому инструменты, такие как BeautifulSoup или Mechanize, не могут быть и речи .... –

Смежные вопросы