<commit_before># coding: utf-8

import re
import requests
from bs4 import BeautifulSoup
import pandas as pd
import logging
from pathlib import Path
import time
from datetime import datetime
import sys


logger = logging.getLogger(__name__)
logging.basicConfig()
logger.setLevel(logging.INFO)

URL_BASE = 'http://www.marinetraffic.com'




def obtem_pagina(url, proxy = None):
    user_agent = {'User-agent': 'Mozilla/5.0'}
    return requests.get(url, headers = user_agent, proxies = proxy)

def cria_pasta(caminho_arquivo):
    pasta = caminho_arquivo.parent
    if not pasta.exists():
        pasta.mkdir(parents=True)

def data_coleta():
    return datetime.utcnow().strftime('%Y-%m-%d %H:%M')

def converte_data(num):
    return time.strftime('%Y-%m-%d %H:%M', time.gmtime(num))

def salva_dataframe_csv(dataframe, caminho_arquivo):
    caminho_arquivo_acum = caminho_arquivo.replace('.csv', '_acumulado.csv')

    dataframe.to_csv(caminho_arquivo_acum, sep=';', index=False, mode='a', decimal=',')
    logger.info('Arquivo {} criado.'.format(caminho_arquivo_acum))

    dataframe.to_csv(caminho_arquivo, sep=';', index=False, mode='w', decimal=',')
    logger.info('Arquivo {} criado.'.format(caminho_arquivo))


# # Navios de interesse

'''
    Crawl dos navios de interesse.

    arquivo_csv - arquivo de saída.
    proxy - proxy se necessário.
'''
def crawl_navios_interesse(arquivo_csv = './output/navios_interesse.csv',
    navios_em_portos_csv='./output/navios_em_portos.csv',
    chegadas_esperadas_csv='./output/chegadas_esperadas.csv', proxy=None,
    limite = None):

    df_navios_em_portos =   pd.read_csv('./output/navios_em_portos.csv', sep=';')
    df_chegadas_esperadas = pd.read_csv('./output/chegadas_esperadas.csv', sep=';')

    urls = df_navios_em_portos.LinkNavio.append(df_chegadas_esperadas.LinkNavio).values

    #urls = [i for i in urls if i.find('MILTON')>0]
    navios = []
    navios_erro = []
    i_limite = 1
    for url in urls:
        # Controle de limite de navios a buscar.
        if limite and i_limite > limite:
                break
        i_limite += 1


        url = URL_BASE + url
        logger.info('Obtendo dados de navio em {}.'.format(url))

        r = obtem_pagina(url, proxy)

        if r.status_code == 200: # Código HTTP de OK.
            soup = BeautifulSoup(r.text, 'lxml')

            detalhes = []

            # Nome do navio
            nome = soup.find('h1', class_='font-200 no-margin').text
            detalhes.append(nome)

            # Tipo. Informação logo abaixo do nome no site.
            tipo = None
            div = soup.find('div', class_='group-ib vertical-offset-10')
            if div:
                tipo = div.text.strip()

            # Latitude e longitude.
            a_posicao = soup.find('a', class_='details_data_link')
            link_posicao =None
            latitude = None
            longitude = None
            if a_posicao:
                if a_posicao['href']:
                    link_posicao = a_posicao['href']
                if a_posicao.text:
                    coord = a_posicao.text
                    coord = [i.strip() for i in coord.split('/')]
                    coord = [i.replace('°','').replace('.',',') for i in coord]
                    latitude, longitude = coord

            # Data (UTC) último sinal recebido.
            span = soup.find('span', text=re.compile('Position Received'))
            data_ultimo_sinal = None
            if span and span.parent and span.parent.strong and span.parent.strong.text:
                texto = span.parent.strong.text.strip()
                match = re.search(r'(\d\d\d\d-\d\d-\d\d\s\d\d:\d\d)', texto)
                if match:
                    data_ultimo_sinal = match.groups()[0]

            # Área geográfica.
            span = soup.find('span', text=mtc.re.compile('Area:'))
            area_geografica = None
            if span and span.parent and span.parent.strong and span.parent.strong.text:
                area_geografica = span.parent.strong.text.strip()



            # Restante das informações.
            div = soup.find('div', class_='row equal-height')
            div_infos = div.find_all('div', class_='col-xs-6')
            for div_ in div_infos:
                detalhes.extend([i.text for i in div_.find_all('b')])

            detalhes.extend([tipo, latitude, longitude,
                data_ultimo_sinal, area_geografica, link_posicao, url, data_coleta()])

            navios.append(detalhes)
        else:
            s = 'Erro código HTTP {} ao obter dados do navio {}.'.format(r.status_code, url)
            logger.error(s)
            navios_erro.append([s,url])

    logger.info('Total de navios sem erro / com erros: {} / {}'.format(len(navios),len(navios_erro)))

    df = pd.DataFrame(navios, columns= ['Nome', 'IMO', 'MMSI', 'Indicativo',
        'Bandeira', 'TipoAIS', 'Tonelagem', 'Porte', 'Comp_Larg', 'Ano',
        'Estado','Tipo', 'Latitude', 'Longitude', 'DataUltimoSinal', 
        'AreaGeografica', 'LinkPosicaoNavio', 'LinkNavio','DataColeta'])

    df = df.replace('-',pd.np.nan)
    df.Porte = df.Porte.str.replace(' t','')
    df['Comprimento'] = df.Comp_Larg.str.extract(r'(\d{0,4}(?:[.,]\d{1,3})?)m', expand=False)
    df['Comprimento'] = df['Comprimento'].str.replace('.',',')
    df['Largura'] = df.Comp_Larg.str.extract(r'(\d{0,4}(?:[.,]\d{1,3})?)m$', expand=False)
    df['Largura'] = df['Largura'].str.replace('.',',')


    # Salva arquivo no diretório indicado.
    caminho_arquivo = Path(arquivo_csv)
    cria_pasta(caminho_arquivo)
    salva_dataframe_csv(df,caminho_arquivo.as_posix())

    df_erro = pd.DataFrame(navios_erro, columns=['Erro','URL'])
    salva_dataframe_csv(df_erro, './navios_erro.csv')



# # Portos brasileiros

# In[236]:

def crawl_portos_brasil(arquivo_csv='./output/portos.csv', proxy=None):
    url = 'https://www.marinetraffic.com/en/ais/index/ports/all/flag:BR/port_type:p'

    tabela_portos = []

    while True:
        logger.info('Capturar portos em: {}'.format(url))
        html_portos = obtem_pagina(url, proxy=proxy).text
        soup = BeautifulSoup(html_portos, 'lxml')

        # Tag <table> dos portos.
        table_portos = soup.find('table', class_='table table-hover text-left')

        # Percorrer todas as linhas da tabela.
        # A primeira linha é o cabeçalho, então iremos pulá-la.
        linhas = table_portos.find_all('tr')
        for linha in linhas[1:]:

            # Cada linha contém uma lista de células com os valores de interesse.
            celulas = linha.find_all('td')

            # Pular propagada que contém apenas uma célula <td>.
            if len(celulas) == 1: continue

            # Coluna da bandeira do país.
            col = celulas[0]
            pais = col.img.attrs['title']
            link_bandeira_pais = col.img['src']

            # Coluna de link para o porto.
            col = celulas[1]
            link_porto = col.a['href']
            nome_porto = col.text.strip()

            # Coluna Codigo.
            col = celulas[2]
            codigo = col.text.strip()

            # Coluna Foto.
            col = celulas[3]
            link_fotos = col.a['href']

            # Coluna Tipo
            col = celulas[4]
            tipo = col.text.strip()

            # Coluna link para mapa do porto.
            col = celulas[5]
            link_mapa_porto = col.a['href']

            # Coluna Navios no porto.
            col = celulas[6]
            link_navios_porto = col.a['href']

            # Coluna link partidas.
            col = celulas[7]
            link_partidas = col.a['href']

            # Coluna link chegadas.
            col = celulas[8]
            link_chegadas = col.a['href']

            # Coluna link chegadas esperadas.
            col = celulas[9]
            link_chegadas_esperadas = col.a['href']

            # Coluna status da cobertura AIS.
            col = celulas[10]
            cobertura_ais = col.div['title']

            # Armazena os dados de cada porto na tabela de portos.
            dados = [pais, nome_porto,codigo, tipo, cobertura_ais, link_bandeira_pais, link_navios_porto,
                     link_chegadas_esperadas, link_chegadas, link_porto, link_fotos,
                     link_mapa_porto, data_coleta()]
            tabela_portos.append(dados)

        # Não há próxima página?
        next_disabled = soup.find('span', class_='next disabled')
        if next_disabled:
            logger.info('Fim da captura de portos.')

            break
        else:
            next_page = soup.find('span', class_='next')
            url = URL_BASE + next_page.a['href']

    cabecalho = ['Pais','Nome','Codigo','Tipo','CoberturaAIS','LinkBandeira','LinkNaviosPorto',
                 'LinkChegadasEsperadas','LinkChegadas','LinkPorto','LinkFotos',
                'LinkMapaPorto', 'DataColeta']
    df = pd.DataFrame(tabela_portos, columns=cabecalho)

    # Issue #3
    df['Id'] = df.LinkPorto.str.extract(r'ports/(\d+)/Brazil', expand=False)

    caminho_arquivo = Path(arquivo_csv)
    cria_pasta(caminho_arquivo)
    salva_dataframe_csv(df, caminho_arquivo.as_posix())

def crawl_navios_em_portos(arquivo_csv='./output/navios_em_portos.csv', proxy=None):
    tabela_navios_porto = []


    df_portos_interesse = pd.read_csv('./input/portos_interesse.csv', sep=';', encoding='latin-1')<commit_msg>Havia faltado retornar lat/long para portos solicitado em  #1. Agora portos também tem collunas lat/long.<commit_after># coding: utf-8

import re
import requests
from bs4 import BeautifulSoup
import pandas as pd
import logging
from pathlib import Path
import time
from datetime import datetime
import sys


logger = logging.getLogger(__name__)
logging.basicConfig()
logger.setLevel(logging.INFO)

URL_BASE = 'http://www.marinetraffic.com'




def obtem_pagina(url, proxy = None):
    user_agent = {'User-agent': 'Mozilla/5.0'}
    return requests.get(url, headers = user_agent, proxies = proxy)

def cria_pasta(caminho_arquivo):
    pasta = caminho_arquivo.parent
    if not pasta.exists():
        pasta.mkdir(parents=True)

def data_coleta():
    return datetime.utcnow().strftime('%Y-%m-%d %H:%M')

def converte_data(num):
    return time.strftime('%Y-%m-%d %H:%M', time.gmtime(num))

def salva_dataframe_csv(dataframe, caminho_arquivo):
    caminho_arquivo_acum = caminho_arquivo.replace('.csv', '_acumulado.csv')

    dataframe.to_csv(caminho_arquivo_acum, sep=';', index=False, mode='a', decimal=',')
    logger.info('Arquivo {} criado.'.format(caminho_arquivo_acum))

    dataframe.to_csv(caminho_arquivo, sep=';', index=False, mode='w', decimal=',')
    logger.info('Arquivo {} criado.'.format(caminho_arquivo))


# # Navios de interesse

'''
    Crawl dos navios de interesse.

    arquivo_csv - arquivo de saída.
    proxy - proxy se necessário.
'''
def crawl_navios_interesse(arquivo_csv = './output/navios_interesse.csv',
    navios_em_portos_csv='./output/navios_em_portos.csv',
    chegadas_esperadas_csv='./output/chegadas_esperadas.csv', proxy=None,
    limite = None):

    df_navios_em_portos =   pd.read_csv('./output/navios_em_portos.csv', sep=';')
    df_chegadas_esperadas = pd.read_csv('./output/chegadas_esperadas.csv', sep=';')

    urls = df_navios_em_portos.LinkNavio.append(df_chegadas_esperadas.LinkNavio).values

    #urls = [i for i in urls if i.find('MILTON')>0]
    navios = []
    navios_erro = []
    i_limite = 1
    for url in urls:
        # Controle de limite de navios a buscar.
        if limite and i_limite > limite:
                break
        i_limite += 1


        url = URL_BASE + url
        logger.info('Obtendo dados de navio em {}.'.format(url))

        r = obtem_pagina(url, proxy)

        if r.status_code == 200: # Código HTTP de OK.
            soup = BeautifulSoup(r.text, 'lxml')

            detalhes = []

            # Nome do navio
            nome = soup.find('h1', class_='font-200 no-margin').text
            detalhes.append(nome)

            # Tipo. Informação logo abaixo do nome no site.
            tipo = None
            div = soup.find('div', class_='group-ib vertical-offset-10')
            if div:
                tipo = div.text.strip()

            # Latitude e longitude.
            a_posicao = soup.find('a', class_='details_data_link')
            link_posicao =None
            latitude = None
            longitude = None
            if a_posicao:
                if a_posicao['href']:
                    link_posicao = a_posicao['href']
                if a_posicao.text:
                    coord = a_posicao.text
                    coord = [i.strip() for i in coord.split('/')]
                    coord = [i.replace('°','').replace('.',',') for i in coord]
                    latitude, longitude = coord

            # Data (UTC) último sinal recebido.
            span = soup.find('span', text=re.compile('Position Received'))
            data_ultimo_sinal = None
            if span and span.parent and span.parent.strong and span.parent.strong.text:
                texto = span.parent.strong.text.strip()
                match = re.search(r'(\d\d\d\d-\d\d-\d\d\s\d\d:\d\d)', texto)
                if match:
                    data_ultimo_sinal = match.groups()[0]

            # Área geográfica.
            span = soup.find('span', text=re.compile('Area:'))
            area_geografica = None
            if span and span.parent and span.parent.strong and span.parent.strong.text:
                area_geografica = span.parent.strong.text.strip()



            # Restante das informações.
            div = soup.find('div', class_='row equal-height')
            div_infos = div.find_all('div', class_='col-xs-6')
            for div_ in div_infos:
                detalhes.extend([i.text for i in div_.find_all('b')])

            detalhes.extend([tipo, latitude, longitude,
                data_ultimo_sinal, area_geografica, link_posicao, url, data_coleta()])

            navios.append(detalhes)
        else:
            s = 'Erro código HTTP {} ao obter dados do navio {}.'.format(r.status_code, url)
            logger.error(s)
            navios_erro.append([s,url])

    logger.info('Total de navios sem erro / com erros: {} / {}'.format(len(navios),len(navios_erro)))

    df = pd.DataFrame(navios, columns= ['Nome', 'IMO', 'MMSI', 'Indicativo',
        'Bandeira', 'TipoAIS', 'Tonelagem', 'Porte', 'Comp_Larg', 'Ano',
        'Estado','Tipo', 'Latitude', 'Longitude', 'DataUltimoSinal',
        'AreaGeografica', 'LinkPosicaoNavio', 'LinkNavio','DataColeta'])

    df = df.replace('-',pd.np.nan)
    df.Porte = df.Porte.str.replace(' t','')
    df['Comprimento'] = df.Comp_Larg.str.extract(r'(\d{0,4}(?:[.,]\d{1,3})?)m', expand=False)
    df['Comprimento'] = df['Comprimento'].str.replace('.',',')
    df['Largura'] = df.Comp_Larg.str.extract(r'(\d{0,4}(?:[.,]\d{1,3})?)m$', expand=False)
    df['Largura'] = df['Largura'].str.replace('.',',')


    # Salva arquivo no diretório indicado.
    caminho_arquivo = Path(arquivo_csv)
    cria_pasta(caminho_arquivo)
    salva_dataframe_csv(df,caminho_arquivo.as_posix())

    df_erro = pd.DataFrame(navios_erro, columns=['Erro','URL'])
    salva_dataframe_csv(df_erro, './navios_erro.csv')



# # Portos brasileiros

# In[236]:

def crawl_portos_brasil(arquivo_csv='./output/portos.csv', proxy=None,
    limite = None):
    url = 'https://www.marinetraffic.com/en/ais/index/ports/all/flag:BR/port_type:p'

    tabela_portos = []

    i_limite = 1
    while True:

        logger.info('Capturar portos em: {}'.format(url))
        html_portos = obtem_pagina(url, proxy=proxy).text
        soup = BeautifulSoup(html_portos, 'lxml')

        # Tag <table> dos portos.
        table_portos = soup.find('table', class_='table table-hover text-left')

        # Percorrer todas as linhas da tabela.
        # A primeira linha é o cabeçalho, então iremos pulá-la.
        linhas = table_portos.find_all('tr')

        for linha in linhas[1:]:
            # Controle de limite de portos a buscar.
            if limite and i_limite > limite:
                    break
            i_limite += 1

            # Cada linha contém uma lista de células com os valores de interesse.
            celulas = linha.find_all('td')

            # Pular propagada que contém apenas uma célula <td>.
            if len(celulas) == 1: continue

            # Coluna da bandeira do país.
            col = celulas[0]
            pais = col.img.attrs['title']
            link_bandeira_pais = col.img['src']

            # Coluna de link para o porto.
            col = celulas[1]
            link_porto = col.a['href']
            nome_porto = col.text.strip()

            # Coluna Codigo.
            col = celulas[2]
            codigo = col.text.strip()

            # Coluna Foto.
            col = celulas[3]
            link_fotos = col.a['href']

            # Coluna Tipo
            col = celulas[4]
            tipo = col.text.strip()

            # Coluna link para mapa do porto.
            col = celulas[5]
            link_mapa_porto = col.a['href']

            # Coluna Navios no porto.
            col = celulas[6]
            link_navios_porto = col.a['href']

            # Coluna link partidas.
            col = celulas[7]
            link_partidas = col.a['href']

            # Coluna link chegadas.
            col = celulas[8]
            link_chegadas = col.a['href']

            # Coluna link chegadas esperadas.
            col = celulas[9]
            link_chegadas_esperadas = col.a['href']

            # Coluna status da cobertura AIS.
            col = celulas[10]
            cobertura_ais = col.div['title']

            # Armazena os dados de cada porto na tabela de portos.
            dados = [pais, nome_porto,codigo, tipo, cobertura_ais, link_bandeira_pais, link_navios_porto,
                     link_chegadas_esperadas, link_chegadas, link_porto, link_fotos,
                     link_mapa_porto, data_coleta()]
            tabela_portos.append(dados)

        # Não há próxima página?
        next_disabled = soup.find('span', class_='next disabled')
        if next_disabled:
            logger.info('Fim da captura de portos.')

            break
        else:
            next_page = soup.find('span', class_='next')
            url = URL_BASE + next_page.a['href']

    cabecalho = ['Pais','Nome','Codigo','Tipo','CoberturaAIS','LinkBandeira','LinkNaviosPorto',
                 'LinkChegadasEsperadas','LinkChegadas','LinkPorto','LinkFotos',
                'LinkMapaPorto', 'DataColeta']
    df = pd.DataFrame(tabela_portos, columns=cabecalho)

    # Issue #3
    df['Id'] = df.LinkPorto.str.extract(r'ports/(\d+)/Brazil', expand=False)

    # Issue #5
    df_latlong = df.LinkMapaPorto.str.extract(
        'centerx:(?P<Longitude>-?\d{,3}\.?\d*)/' +
        'centery:(?P<Latitude>-?\d{,3}\.?\d*)',
        expand=True)
    df_latlong['Latitude'] = df_latlong.Latitude.str.replace('.', ',')
    df_latlong['Longitude'] = df_latlong.Longitude.str.replace('.', ',')
    df = df.join(df_latlong)


    caminho_arquivo = Path(arquivo_csv)
    cria_pasta(caminho_arquivo)
    salva_dataframe_csv(df, caminho_arquivo.as_posix())

def crawl_navios_em_portos(arquivo_csv='./output/navios_em_portos.csv', proxy=None):
    tabela_navios_porto = []


    df_portos_interesse = pd.read_csv('./input/portos_interesse.csv', sep=';', encoding='latin-1')
{'fraction_non_alphanumeric': 0.13422922459067038, 'fraction_numerical': 0.004942848316342292, 'mean_word_length': 2.334420600858369, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 14, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4521310', 'n_tokens_mistral': 6893, 'n_tokens_neox': 6698, 'n_words': 1285}