@@ -1,5 +1,5 @@
1from lxml import html
1from lxml import html
2−from urllib import urlencode
2+from urllib import urlencode, unquote
3from urlparse import urlparse, urljoin
3from urlparse import urlparse, urljoin
4from cgi import escape
4from cgi import escape
5from lxml.etree import _ElementStringResult
5from lxml.etree import _ElementStringResult
@@ -11,32 +11,64 @@ title_xpath = None
11suggestion_xpath = ''
11suggestion_xpath = ''
12results_xpath = ''
12results_xpath = ''
15+if xpath_results is list, extract the text from each result and concat the list
16+if xpath_results is a xml element, extract all the text node from it ( text_content() method from lxml )
17+if xpath_results is a string element, then it's already done
14−def extract_url(xpath_results):
19+def extract_text(xpath_results):
16− parsed_search_url = urlparse(search_url)
17 if type(xpath_results) == list:
20 if type(xpath_results) == list:
21+ # it's list of result : concat everything using recursive call
18 if not len(xpath_results):
22 if not len(xpath_results):
19 raise Exception('Empty url resultset')
23 raise Exception('Empty url resultset')
25+ for e in xpath_results:
26+ result = result + extract_text(e)
20− if type(xpath_results[0]) == _ElementStringResult:
28+ elif type(xpath_results) == _ElementStringResult:
21− url = ''.join(xpath_results)
30+ return ''.join(xpath_results)
22− if url.startswith('//'):
23− url = parsed_search_url.scheme+url
24− elif url.startswith('/'):
25− url = urljoin(search_url, url)
28− url = xpath_results[0].attrib.get('href')
30− url = xpath_results.attrib.get('href')
33+ return xpath_results.text_content()
36+def extract_url(xpath_results):
37+ url = extract_text(xpath_results)
31− if not url.startswith('http://') and not url.startswith('https://'):
39+ if url.startswith('//'):
32− url = 'http://'+url
40+ # add http or https to this kind of url //example.com/
41+ parsed_search_url = urlparse(search_url)
42+ url = parsed_search_url.scheme+url
43+ elif url.startswith('/'):
44+ # fix relative url to the search engine
45+ url = urljoin(search_url, url)
48+ url = normalize_url(url)
53+def normalize_url(url):
33 parsed_url = urlparse(url)
54 parsed_url = urlparse(url)
56+ # add a / at this end of the url if there is no path
34 if not parsed_url.netloc:
57 if not parsed_url.netloc:
35 raise Exception('Cannot parse url')
58 raise Exception('Cannot parse url')
36 if not parsed_url.path:
59 if not parsed_url.path:
37 url += '/'
60 url += '/'
62+ # FIXME : hack for yahoo
63+ if parsed_url.hostname == 'search.yahoo.com' and parsed_url.path.startswith('/r'):
67+ return unquote(p[mark+3:]).decode('utf-8')
38 return url
69 return url
40def request(query, params):
72def request(query, params):
41 query = urlencode({'q': query})[2:]
73 query = urlencode({'q': query})[2:]
42 params['url'] = search_url.format(query=query)
74 params['url'] = search_url.format(query=query)
@@ -50,15 +82,19 @@ def response(resp):
50 if results_xpath:
82 if results_xpath:
51 for result in dom.xpath(results_xpath):
83 for result in dom.xpath(results_xpath):
52 url = extract_url(result.xpath(url_xpath))
84 url = extract_url(result.xpath(url_xpath))
53− title = ' '.join(result.xpath(title_xpath))
85+ title = extract_text(result.xpath(title_xpath)[0 ])
54− content = escape(' '.join(result.xpath(content_xpath)))
86+ content = extract_text(result.xpath(content_xpath)[0])
55 results.append({'url': url, 'title': title, 'content': content})
87 results.append({'url': url, 'title': title, 'content': content})
89+ for url, title, content in zip(
57− for content, url, title in zip(dom.xpath(content_xpath), map(extract_url, dom.xpath(url_xpath)), dom.xpath(title_xpath)):
90+ map(extract_url, dom.xpath(url_xpath)), \
91+ map(extract_text, dom.xpath(title_xpath)), \
92+ map(extract_text, dom.xpath(content_xpath)), \
58 results.append({'url': url, 'title': title, 'content': content})
94 results.append({'url': url, 'title': title, 'content': content})
60 if not suggestion_xpath:
96 if not suggestion_xpath:
61 return results
97 return results
62 for suggestion in dom.xpath(suggestion_xpath):
98 for suggestion in dom.xpath(suggestion_xpath):
63− results.append({'suggestion': escape(''.join(suggestion.xpath('.//text()')))})
99+ results.append({'suggestion': extract_text(suggestion)})
64 return results
100 return results