Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*.pyc
*.coverage
.eggs
dist
build
packtrack.egg-info
Expand Down
6 changes: 4 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
language: python

before_install: pip install -r requirements.txt
before_install:
- python setup.py install
- pip install -r requirements-dev.txt

script: nosetests
script: nosetests
6 changes: 3 additions & 3 deletions packtrack/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from correios import EncomendaRepository
from royal import RoyalMail
from dhl_gm import DhlGmTracker
from .correios import EncomendaRepository
from .royal import RoyalMail
from .dhl_gm import DhlGmTracker


class Correios(object):
Expand Down
5 changes: 2 additions & 3 deletions packtrack/correios.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def get(self, numero, auth=None):
return func(numero, **kwargs)

def _init_scraper(self, backend):
from scraping import CorreiosWebsiteScraper, CorreiosRastroService
from .scraping import CorreiosWebsiteScraper, CorreiosRastroService
if backend is None:
backend = 'www2'

Expand All @@ -34,10 +34,9 @@ def __init__(self, numero):
self.status = []

def adicionar_status(self, status):
d = datetime
self.status.append(status)
t_format = self.validar_data(status.data)
self.status.sort(lambda x, y: 1 if d.strptime(x.data, t_format) > d.strptime(y.data, t_format) else -1)
self.status.sort(key=lambda s: datetime.strptime(s.data, t_format))

def validar_data(self, data):
if re.match('^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$', data):
Expand Down
45 changes: 16 additions & 29 deletions packtrack/scraping.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import os
import re
from HTMLParser import HTMLParser
from html import unescape

from BeautifulSoup import BeautifulSoup
from bs4 import BeautifulSoup
import requests
from requests.exceptions import RequestException
from zeep import Client as Zeep
from zeep.cache import InMemoryCache
from zeep.transports import Transport

from correios import Encomenda, Status
from .correios import Encomenda, Status


class CorreiosWebsiteScraper(object):
Expand Down Expand Up @@ -46,49 +46,36 @@ def get_encomenda_info(self, numero):
except RequestException:
return None

html = response.content

html = response.text
if html:
try:
html = html.decode('latin-1')
except UnicodeDecodeError:
pass
encomenda = Encomenda(numero)
for status in self._get_all_status_from_html(html):
encomenda.adicionar_status(status)
return encomenda

def _text(self, value):
value = BeautifulSoup(value.strip()).text
return value.replace(' ', ' ')
text = BeautifulSoup(value.strip(), 'html.parser').text
return re.sub(r'[\s\t]+', ' ', text)

def _get_all_status_from_html(self, html):
status = []
html_parser = HTMLParser()
if "<table" not in html:
return status
html_info = re.search('.*(<table.*</table>).*', html, re.S)
if not html_info:
return status

table = html_info.group(1)
soup = BeautifulSoup(table)

for tr in soup.table:
# O bs4 converte o &nbsp; para \xa0 ao invés de espaço.
clean_html = html.replace('&nbsp;', ' ')
soup = BeautifulSoup(clean_html, 'html.parser')
for tr in soup.select('table.sro tr'):
try:
tds = tr.findAll('td')
except AttributeError:
continue
for td in tds:
content = td.renderContents().replace('\r', ' ') \
.split('<br />')
content = td.encode_contents().decode().replace('\r', ' ').split('<br/>')
class_ = td['class']
if class_ == 'sroDtEvent':
if 'sroDtEvent' in class_:
data = '%s %s' % (content[0].strip(), content[1].strip())
local = '/'.join(self._text(content[2]).rsplit(' / ', 1)).upper()
elif class_ == 'sroLbEvent':
situacao = html_parser.unescape(self._text(content[0]))
detalhes = html_parser.unescape(self._text(content[1]))
local = '/'.join(self._text(content[2]).rsplit(' / ', 1)).upper().rstrip('/')
elif 'sroLbEvent' in class_:
situacao = unescape(self._text(content[0]))
detalhes = unescape(self._text(content[1]))
if detalhes:
detalhes = u'%s %s' % (situacao, detalhes)
status.append(Status(data=data, local=local,
Expand Down
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nose
8 changes: 0 additions & 8 deletions requirements.txt

This file was deleted.

7 changes: 3 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

setup(
name='packtrack',
version='1.6',
version='2.0',
packages=['packtrack'],
author='Ale Borba',
author_email='ale.borba@codingforchange.com',
Expand All @@ -13,9 +13,8 @@
url='https://github.com/aleborba/packtrack',
long_description='API Python para obter informacoes de encomendas. Para mais detalhes veja a documentacao no Github: https://github.com/aleborba/packtrack/blob/master/README.textile',
install_requires=[
'BeautifulSoup >= 3.1.0',
'requests >= 0.14.2',
'beautifulsoup4 >= 4.3.2',
'requests',
'beautifulsoup4 >= 4.9.3',
'lxml >= 2.3.5',
'zeep >= 1.6.0',
],
Expand Down
18 changes: 7 additions & 11 deletions tests/correios_api_test.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import unittest

from mock import Mock
from mockito import when
from unittest import TestCase
from unittest.mock import Mock

from packtrack import Correios


class CorreiosTest(unittest.TestCase):
class CorreiosTest(TestCase):

def test_should_use_repository_to_get_encomenda(self):
encomenda_repository_mock = Mock()
when(encomenda_repository_mock).get('123', auth=None) \
.thenReturn('encomenda123')

encomenda_repository_mock.get.return_value = 'encomenda123'
Correios._backends[None] = encomenda_repository_mock

assert Correios.track('123') == 'encomenda123'
encomenda_repository_mock.get.assert_called_with('123', auth=None)

def test_service_should_receive_auth(self):
auth = ('mi', 'mimi')
encomenda_repository_mock = Mock()
when(encomenda_repository_mock).get('123', auth=auth) \
.thenReturn('encomenda123')

encomenda_repository_mock.get.return_value = 'encomenda123'
Correios._backends['service'] = encomenda_repository_mock

assert Correios.track(
'123', backend='service', auth=auth) == 'encomenda123'
encomenda_repository_mock.get.assert_called_with('123', auth=auth)
12 changes: 6 additions & 6 deletions tests/correios_test.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import unittest

from mock import Mock
from mockito import *
from unittest.mock import Mock

from packtrack.correios import Encomenda, Status, EncomendaRepository


class EncomendaRepositoryTest(unittest.TestCase):

def test_should_get_encomenda_by_numero(self):
encomenda_123 = Status(data='2009-01-28 17:49:00')

correios_website_scraper_mock = Mock()
when(correios_website_scraper_mock).get_encomenda_info('123', auth=None).thenReturn(encomenda_123)
correios_website_scraper_mock.get_encomenda_info.return_value = encomenda_123

repository = EncomendaRepository()
repository.correios_website_scraper = correios_website_scraper_mock
encomenda = repository.get('123')
assert encomenda
assert encomenda.data == '2009-01-28 17:49:00'
correios_website_scraper_mock.get_encomenda_info.assert_called_with('123', auth=None)

def test_select_default_backend(self):
repository = EncomendaRepository()
Expand Down
20 changes: 9 additions & 11 deletions tests/scraping_test.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# encoding: UTF-8
import os
import unittest

import mock
from unittest.mock import Mock

from packtrack.scraping import CorreiosWebsiteScraper
from packtrack.dhl_gm import DhlGmTracker
Expand All @@ -17,14 +16,13 @@ def _assert_status(self, status, data, local, situacao, detalhes):
self.assertEqual(detalhes, status.detalhes)

def test_should_get_data_from_correios_website(self):
example_file = open('%s/tests/correios_website/exemplo_rastreamento_correios1.html' % os.getcwd())
sample_html = example_file.read()
example_file.close()
with open(f'{os.getcwd()}/tests/correios_website/exemplo_rastreamento_correios1.html', 'r', encoding='latin-1') as f:
sample_html = f.read()

http_client_mock = mock.Mock()
response_mock = mock.Mock()
http_client_mock = Mock()
response_mock = Mock()
http_client_mock.post.return_value = response_mock
response_mock.content = sample_html
response_mock.text = sample_html

correios_website_scraper = CorreiosWebsiteScraper(http_client_mock)
numero = 'PJ859656941BR'
Expand All @@ -47,10 +45,10 @@ class CorreiosTimeoutTest(unittest.TestCase):

def test_timeout_undefined(self):

http_client_mock = mock.Mock()
response_mock = mock.Mock()
http_client_mock = Mock()
response_mock = Mock()
http_client_mock.post.return_value = response_mock
response_mock.content = ''
response_mock.text = ''
TIMEOUT = 3
scraper = CorreiosWebsiteScraper(http_client_mock, timeout=TIMEOUT)
scraper.get_encomenda_info('ES446391025BR')
Expand Down