Ultimas do CanalQb

Python - Sqlite - Tratamento com 2 tabelas

Python - Sqlite - Tratamento com 2 tabelas
Canal Qb

A primeira tabela terá apenas uma coluna para armazenar o último valor da faixa gerada. 
A segunda tabela conterá todas as consultas com suas respectivas respostas.

Aqui está o código modificado: 
import asyncio
import aiohttp
import sqlite3
from bs4 import BeautifulSoup


async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            html = await response.text()
            soup = BeautifulSoup(html, 'html.parser')
            title = soup.find('title')
            if title and "Page Not Found" not in title.text:
                return f"{url.split('/')[-1]}: {title.text}"
            print(title.text)


async def fetch_all(urls):
    responses = await asyncio.gather(*[fetch(url) for url in urls])
    return [r for r in responses if r]


async def insert_last_value(conn, value):
    cursor = conn.cursor()
    cursor.execute("INSERT INTO last_value (value) VALUES (?)", (value,))
    conn.commit()


async def get_last_value(conn):
    cursor = conn.cursor()
    cursor.execute("SELECT value FROM last_value ORDER BY ROWID DESC LIMIT 1")
    result = cursor.fetchone()
    return result[0] if result else None


async def insert_response(conn, value):
    cursor = conn.cursor()
    cursor.execute("INSERT INTO responses (value) VALUES (?)", (value,))
    conn.commit()


async def main():
    try:
        db_conn = sqlite3.connect("urls.db")
        cursor = db_conn.cursor()
        cursor.execute('''CREATE TABLE IF NOT EXISTS last_value (value INTEGER)''')
        cursor.execute('''CREATE TABLE IF NOT EXISTS responses (value TEXT UNIQUE)''')

        last_value = await get_last_value(db_conn)
        if not last_value:
            last_value = 0

        end_value = int(input("Digite o valor final: "))
        urls = [f'https://pt.aliexpress.com/item/{i}.html' for i in range(last_value + 1, end_value + 1)]
        responses = await fetch_all(urls)

        for response in responses:
            if response:
                value = response.split(':')[0]
                try:
                    await insert_response(db_conn, value)
                    print(f"Valor {value} inserido na tabela de respostas")
                except sqlite3.IntegrityError:
                    print(f"Valor {value} já existe na tabela de respostas")

        await insert_last_value(db_conn, end_value)
        print(f"Último valor da faixa ({end_value}) inserido na tabela de último valor")

    except RuntimeError:
        pass
    finally:
        db_conn.close()


loop = asyncio.get_event_loop()
loop.run_until_complete(main())
O código modificado tem quatro funções de banco de dados:

insert_last_value(): insere o último valor da faixa gerada na tabela last_value.
get_last_value(): retorna o último valor da tabela last_value.
insert_response(): insere uma consulta e sua resposta na tabela responses.
main(): obtém o último valor da tabela last_value, gera uma nova faixa de URLs, faz as consultas e insere os resultados na tabela responses. Em seguida, o último valor da faixa gerada é inserido na tabela last_value.
Com estas modificações, você pode executar o script várias vezes, e ele começará a gerar uma nova faixa de URLs a partir do último valor inserido na tabela

--**--
Possíveis erros:

O erro "AttributeError: 'NoneType' object has no attribute 'text'" ocorre porque a variável "title" está sendo definida como "None" em algumas páginas e, portanto, não possui o atributo "text".

Para corrigir esse erro, você pode adicionar uma verificação para garantir que a variável "title" não seja "None" antes de tentar acessar o atributo "text". Por exemplo: 
async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            html = await response.text()
            soup = BeautifulSoup(html, 'html.parser')
            title = soup.find('title')
            if title and "Page Not Found" not in title.text:
                return f"{url.split('/')[-1]}: {title.text}"
            elif title:
                print(title.text)
            else:
                print(f"Não foi possível encontrar o título da página: {url}")

Dessa forma, se a variável "title" for "None", será impressa uma mensagem indicando que não foi possível encontrar o título da página.

--**--

Para atualizar a linha existente na tabela "last_value" em vez de criar uma nova linha toda vez que o script é executado, você pode modificar a função "main" da seguinte forma: 
async def main():
    try:
        db_conn = sqlite3.connect("urls.db")
        cursor = db_conn.cursor()
        cursor.execute('''CREATE TABLE IF NOT EXISTS last_value (value INTEGER)''')
        cursor.execute("SELECT value FROM last_value")
        row = cursor.fetchone()
        if row is None:
            last_value = 0
        else:
            last_value = row[0]
        end_value = int(input("Digite o valor final: "))
        urls = [f'https://pt.aliexpress.com/item/{i}.html' for i in range(last_value + 1, end_value + 1)]
        responses = await fetch_all(urls)
        for response in responses:
            if response:
                value = response.split(':')[0]
                try:
                    await insert_into_db(db_conn, value)
                    print(f"Valor {value} inserido no banco de dados")
                except sqlite3.IntegrityError:
                    print(f"Valor {value} já existe no banco de dados")
        cursor.execute("REPLACE INTO last_value (value) VALUES (?)", (end_value,))
        db_conn.commit()
    except RuntimeError:
        pass
    finally:
        db_conn.close()
Essa modificação primeiro verifica se existe uma linha na tabela "last_value" e, em seguida, define o valor inicial para a geração de URLs com base no valor existente na tabela. Depois de gerar as URLs e inserir as respostas na tabela "urls", a função atualiza o valor existente na tabela "last_value" usando a cláusula "REPLACE INTO", que substitui a linha existente se ela já existe ou insere uma nova linha se ainda não existe.

--**--

o código e parece que acidentalmente excluí a função insert_into_db. Para corrigir o erro, basta adicionar novamente a definição da função insert_into_db ao código, como mostrado abaixo: 
import asyncio
import aiohttp
import sqlite3
from bs4 import BeautifulSoup

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            html = await response.text()
            soup = BeautifulSoup(html, 'html.parser')
            title = soup.find('title')
            if title and "Page Not Found" not in title.text:
                return f"{url.split('/')[-1]}: {title.text}"
            print(title.text)

async def fetch_all(urls):
    responses = await asyncio.gather(*[fetch(url) for url in urls])
    return [r for r in responses if r]

async def insert_into_db(conn, table_name, value):
    cursor = conn.cursor()
    cursor.execute(f"INSERT INTO {table_name} (value) VALUES (?)", (value,))
    conn.commit()

async def main():
    try:
        db_conn = sqlite3.connect("urls.db")
        cursor = db_conn.cursor()
        cursor.execute('''CREATE TABLE IF NOT EXISTS last_value (value INTEGER)''')
        cursor.execute('''CREATE TABLE IF NOT EXISTS urls (value TEXT UNIQUE)''')
        cursor.execute("SELECT value FROM last_value")
        row = cursor.fetchone()
        if row:
            last_value = row[0]
        else:
            last_value = 0
        end_value = int(input("Digite o valor final: "))
        urls = [f'https://pt.aliexpress.com/item/{i}.html' for i in range(last_value + 1, end_value + 1)]
        responses = await fetch_all(urls)
        for response in responses:
            if response:
                value = response.split(':')[0]
                try:
                    await insert_into_db(db_conn, 'urls', value)
                    print(f"Valor {value} inserido na tabela urls")
                except sqlite3.IntegrityError:
                    print(f"Valor {value} já existe na tabela urls")
        cursor.execute("REPLACE INTO last_value (value) VALUES (?)", (end_value,))
        db_conn.commit()
        print(f"Último valor inserido na tabela last_value: {end_value}")
    except RuntimeError:
        pass
    finally:
        db_conn.close()

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Com essas mudanças, o script agora deve funcionar corretamente. Verifique se o erro foi resolvido.

--**--

Para informar o título na mensagem de impressão, você pode alterar a função insert_into_db() para receber dois parâmetros: value e title. Em seguida, você pode atualizar a mensagem de impressão para exibir o valor e o título. Veja o código abaixo com as alterações necessárias: 
async def insert_into_db(conn, value, title):
    cursor = conn.cursor()
    cursor.execute("INSERT INTO urls (value, title) VALUES (?, ?)", (value, title))
    conn.commit()

# ...

for response in responses:
    if response:
        value, title = response.split(':')
        try:
            await insert_into_db(db_conn, value, title.strip())
            print(f"Valor {value} com título '{title.strip()}' inserido na tabela urls")
        except sqlite3.IntegrityError:
            print(f"Valor {value} já existe na tabela urls")
Isso deve imprimir uma mensagem informando o título junto com o valor que foi inserido na tabela.

--**--

se você quiser manter apenas o valor na tabela urls e exibir o título apenas no print, você pode fazer a seguinte modificação: 
async def insert_into_db(conn, value):
    cursor = conn.cursor()
    cursor.execute("INSERT INTO urls (value) VALUES (?)", (value,))
    conn.commit()

# ...

for response in responses:
    if response:
        value, title = response.split(':')
        try:
            await insert_into_db(db_conn, value)
            print(f"Valor {value} com título '{title.strip()}' inserido na tabela urls")
        except sqlite3.IntegrityError:
            print(f"Valor {value} já existe na tabela urls")
Isso deve imprimir uma mensagem com o título e inserir apenas o valor na tabela urls.

Nenhum comentário

Comente só assim vamos crescer juntos!

Observação: somente um membro deste blog pode postar um comentário.