Sorva, Swig e Pesquise Com Playwright, OpenAI e MongoDB Atlas Search
Avalie esse Tutorial
44The Secret Lives of Mormon Wives,
Se você ainda não experimentou um soda “dirty, eu o recomendamos. É uma combinação interessantes de qualquer soda de sua escolha, metade a metade ou natas e Xaropes aromáticos. Se você não curte soda, vai odiá-lo, mas temo que isso seja um dado. Admito que estava cético, mas se você preferir soda como sua bebida, sua maior conclusão será se perguntar quais outras coisas delicadas as pessoas de Utá estão ocultando do resto de nós.
Depois de consultar os profissionais (uma pesquisa muito rápida no Google), verifiquei que Swig é “home of the original dirty soda.”. J
Vamos usar o Playwright para raspar o menu com os componentes de seu website, as saídas estruturadas da OpenAI para nos ajudar a decidir quais bebidas são mais apropriadas para cada estação, e o MongoDB Atlas Search para filtrar nossos sodas "dirty" com base em seus componentes e o que desejamos.
Antes de começarmos, Go essas plataformas com um pouco mais de detalhes, para que estejamos todos na mesma página.
O Playwright é uma poderosa ferramenta de automação de navegador que foi construída pela Microsoft. É útil para sites executados em mecanismos de renderização modernos, como o Storeium (o Google Chrome é executado nele), Firefox e WebKit, pois permite que os desenvolvedores criem novas páginas do navegador, abram vários URLs e até mesmo permite que você interaja com todos os elementos localizados em uma página.
O Playwright foi escolhido para este tutorial por ser simples retornar os elementos de um site, especialmente de sites dinâmicos, como o que estamos raspando. Embora haja uma série de outras capacidades incríveis para o Playwright, ele é ideal para o nosso caso de uso, pois nossos itens de bebida são carregados usando JavaScript após o carregamento da página inicial. Com outros raspadores de web Python mais tradicionais, eu estava recebendo erros de tempo limite ou listas vazias, pois os itens de menu não estavam incorporados no HTML bruto do site. O Playwright, por outro lado, pode lidar muito bem com a execução do JavaScript e espera que o conteúdo carregue totalmente antes de obter as informações de que precisamos.
As novas Saídas estruturadas do OpenAI garantem que qualquer resposta da tenha exatamente a maneira especificada pelo desenvolvedor. Isso funciona forçando qualquer modelo que você use (estamos usando GPT- API 4o) a ter uma resposta que corresponda ao esquema fornecido pelo desenvolvedor. Este tutorial está usando-o para garantir que as bebidas do menu Swig sejam mostradas em um JSON formato estruturado, já que queremos analisar as respostas do modelo mais tarde no Go tutorial. como fazer isso em detalhes no tutorial!
O MongoDB Atlas Search é uma pesquisa de texto completo incorporada dentro do MongoDB Atlas, o serviço de banco de banco de dados em nuvem do MongoDBpara desenvolvedores. É crucial para este tutorial, pois salvaremos nossos itens de menu raspados em um cluster Atlas e, em seguida, criaremos um pipeline de agregação nos dados para descobrir quais bebidas correspondem à nossa estação e aos nossos componentes específicos.
Esses pré-requisitos são cruciais para garantir que sejamos bem-sucedidos neste tutorial.
- Um IDE de sua escolha: este tutorial usa um bloco de notas doGoogle CoLab. Sinta-se à vontade para acompanhar.
- Chave de API OpenAI: você precisará pagar para acessar uma chave de API.
- Cluster MongoDB Atlas : Verifique se você está usando a camada grátis, se definiu seu endereço IP como "access from anywhere, " e se copiou a string de conexão para um local seguro para referência futura.
Depois de salvar sua chave de API OpenAI em um local seguro, provisionar o cluster do MongoDB Atlas e salvar a string de conexão em um local seguro, você estará pronto para começar!
Antes de escrever nossa função principal para raspar o website, precisamos ter certeza de que realmente inspecionamos o website que queremos raspar para que possamos descobrir corretamente onde ficam as informações que queremos.
Vá até Swig, clique na opção "Dirty Dr Pepper " ou em qualquer opção de soda de sua escolha e, em seguida, clique na loja American Fork. Isso é para ver todos os itens de menu disponíveis para um local. Você pode escolher qualquer local que quiser. rsrsrsrsrsrsrsrsrsrsrsrsrsrsrsrsrsrs,smites pelo, mas por ele porque foi o primeiro a ser exibido.
Em seguida, você verá todos os itens de menu desse local, conforme mostrado abaixo:
Agora, podemos clicar em qualquer soda, clique com o botão direito do mouse para inspecionar a página e ver com o que estamos trabalhando.
A primeira coisa que gostaria de destacar é que este website é um website dinâmico. Como posso saber disso?
Percebo que, quando TENTO inspecionar um item de menu para descobrir como raspar nosso HTML, as informações estão localizadas dentro de um iframe, o que significa que o conteúdo que pretendo raspar é HTML incorporado em outra página da Web. A partir deste exemplo, posso ver que tudo o que gostaria de encontrar (e sabe disso porque destaquei e inspeccionei outras partes, como o nome "Dirty Dr Pepper " e os componentes "Dr Pepper + Coconut (120 - 440 Calories) ") está aninhado sob o mesmo iframe URL, https://swig-orders.crispknow.com/tabs/locations/menu.
Então, o que média um website dinâmico? Isso significa que não posso simplesmente raspar o HTML do nível superior diretamente, pois o site está mudando e não carrega inteiramente de uma Go vez. Felizmente, o Playwright é um raspador que suporta esperar o carregamento dos outros elementos da página antes de raspar, mas nem todos os raspadores da web são iguais nisso. Antes de perceber isso, e ao usar um raspador diferente para tentar atingir meu objetivo, eu estava obtendo saídas vazias toda vez que executava meu código. Então, por favor, inspecione sua página da web antes de tentar raspar!
Depois de ter uma compreensão sólida do site que estamos tentando raspar, vamos escrever nossa função de raspagem.
Então agora, vamos raspar todos os itens do menu que o Swig oferece para ver quais combinações são mais adequadas para o queda. Queremos obter o nome de cada item do menu e sua descrição. Um exemplo disso é o nome "Dirty Dr Pepper 440 120 a descrição "Dr.
Para fazer isso, vamos primeiro instalar o próprio Playwright. Isso pode ser feito com uma simples declaração
pip
e lembre-se de que estamos executando isso em nosso bloco de anotações doGoogle Coab:1 !pip install playwright 2 !playwright install
Agora, vamos definir nossas importações. Como estamos usando um bloco de anotações, precisamos usar
async
. Se você estiver trabalhando localmente por meio do seu IDE, fique à vontade para usar sync
.1 import asyncio 2 from playwright.async_api import async_playwright
Vamos usar o nome
swigScraper
para nossa definição. Mais uma vez, vamos usar async
e, em seguida, o modo headless, pois estamos usando um laptop. Saiba mais sobre quando usar o modo headless versus headless.Também queremos ter certeza de que estamos usando a URL correta . Lembre-se do que foi mencionado acima, queremos usar o URL localizado dentro do iframe do qual nossos elementos estão sendo gerados dinamicamente. Não queremos o URL normal do site Swig .
1 async def swigScraper(): 2 async with async_playwright() as playwright: 3 4 browser = await playwright.chromium.launch(headless=True) 5 page = await browser.new_page() 6 7 # make sure to have the correct URL 8 await page.goto('https://swig-orders.crispnow.com/tabs/locations/menu')
Como a página da web que estamos tentando raspar tem muitos elementos ocultos, vamos primeiro rolar pelo menu para ver o que carrega depois de cerca de um minuto. Em seguida, podemos clicar com o botão direito do mouse e inspecionar a página para ver onde nosso nome e descrição estão aninhados. Depois de rolar por um minuto, destaquei o nome da bebida e, em seguida, cliquei com o botão direito e selecionei "inspect. " Esta captura de tela mostra meu resultado:
Como podemos ver nesta captura de tela, precisamos esperar o carregamento de nosso
ion-card-content
antes de podermos ver onde as informações que queremos estão. Isso nos permite terminar nossa função com um wait_for_selector
dizendo que queremos esperar até que esse seletor específico carregue:1 await page.wait_for_selector('ion-card-content', state='attached', timeout=60000) 2 3 4 # our items names and descriptions are all located in this area 5 items = await page.query_selector_all('ion-card-content')
Agora, podemos criar uma lista para armazenar nosso menu, percorrer o HTML e pegar o que precisamos, extrair nosso texto e torná-lo bonito:
1 menu = [] 2 3 for item in items: 4 result = {} 5 6 name = await item.query_selector('p.text-h3') 7 description = await item.query_selector('p.text-b2') 8 9 # use inner text to extract our info 10 if name and description: 11 result = {} 12 result['name'] = await name.inner_text() 13 result['description'] = await description.inner_text() 14 menu.append(result) 15 16 for item in menu: 17 print(f"Name: {item['name']}, Description: {item['description']}") 18 19 await browser.close() 20 return menu 21 22 scraped_menu = await swigScraper() 23 print(scraped_menu)
Nossos resultados ficarão assim:
Agora que temos todos os itens do nosso menu bem formatados, vamos usar as saídas estruturadas do OpenAI para saber quais bebidas são perfeitas para cada estação e por que!
Certifique-se de ter sua chave de API OpenAI pronta! Iremos usá-lo nesta seção.
Vamos usar saídas estruturadas para que possamos informar ao modelo exatamente o que estamos procurando e como queremos que nossa saída seja estilizada.
Nosso primeiro passo é instalar o OpenAI:
1 !pip install openai
Agora, vamos importar
openai
junto com json
e getpass
para nossa chave de API OpenAI.1 import openai 2 import json 3 import getpass
Usando
getpass
, insira sua chave de API para que seja fácil usarmos esta seção do tutorial.1 # put in your OpenAI API key here 2 openai_api_key = getpass.getpass(prompt= "Put in OpenAI API Key here")
Antes de começarmos, precisamos garantir que nosso menu esteja formatado corretamente para que o OpenAI e nosso modelo entendam. Podemos fazer isso colocando todas as nossas bebidas e suas descrições em uma única string. Também queremos informar à OpenAI nosso prompt para saber o que exatamente é e quais bebidas e componentes estão disponíveis. Vou informar ao nosso modelo que eles são os melhores mestrandos de soda que já vi e estou fornecendo uma lista de nossos soda com suas descrições. Também gostaria de perguntar quais sodas são melhores para cada estação (primavera, verão, queda, verão) com base em suas descrições:
1 def swigJoined(scraped_menu): 2 drink_list = [] 3 4 # just formatting our menu from above 5 for drink in scraped_menu: 6 drink_format = f"{drink['name']}: {drink['description']}]" 7 drink_list.append(drink_format) 8 9 # put all the drinks into a single string for OpenAI to understand it 10 drink_string = "\n".join(drink_list) 11 12 # we have to tell OpenAI which drinks/combinations are available 13 prompt = ( 14 "You are the best soda mixologist Utah has ever seen! This is a list of sodas and their descriptions, or ingredients:\n" 15 f"{drink_string}\n\n Please sort each and every drink provided into spring, summer, fall, or winter seasons based on their ingredients\n" 16 "and give me reasonings as to why by stating which ingredients make it best for each season. For example, cinnamon is more fall, but peach\n" 17 "is more summer." 18 ) 19 20 return prompt
Agora, vamos gerar nosso prompt usando o menu que raspamos. Usaremos nosso prompt abaixo em nossa parte de saídas estruturadas deste tutorial:
1 my_prompt = swigJoined(scraped_menu) 2 openai.api_key = openai_api_key
Agora que isso está pronto, podemos usar nossa chamada estruturada e JSON schema. Para obter ajuda sobre esta parte, consulte a documentação:
Podemos ver na seção "extracting structured data from unstructured data " que a solicitação deve seguir estas especificações:
1 POST /v1/chat/completions 2 { 3 "model": "gpt-4o-2024-08-06", 4 "messages": [ 5 { 6 "role": "system", 7 "content": "Extract action items, due dates, and owners from meeting notes." 8 }, 9 { 10 "role": "user", 11 "content": "...meeting notes go here..." 12 } 13 ], 14 "response_format": { 15 "type": "json_schema", 16 "json_schema": { 17 "name": "action_items", 18 "strict": true, 19 "schema": { 20 "type": "object", 21 "properties": { 22 "action_items": { 23 "type": "array", 24 "items": { 25 "type": "object", 26 "properties": { 27 "description": { 28 "type": "string", 29 "description": "Description of the action item." 30 }, 31 "due_date": { 32 "type": ["string", "null"], 33 "description": "Due date for the action item, can be null if not specified." 34 }, 35 "owner": { 36 "type": ["string", "null"], 37 "description": "Owner responsible for the action item, can be null if not specified." 38 } 39 }, 40 "required": ["description", "due_date", "owner"], 41 "additionalProperties": false 42 }, 43 "description": "List of action items from the meeting." 44 } 45 }, 46 "required": ["action_items"], 47 "additionalProperties": false 48 } 49 } 50 } 51 }
Então, podemos pegar esse código de esqueleto e torná-lo nosso. Este tutorial usa a GPT-4o, mas fique à vontade para usar a GPT com a qual se sentir mais familiarizado:
1 response = openai.chat.completions.create( 2 model="gpt-4o-2024-08-06", 3 messages=[ 4 {"role": "system", "content": "You are the best soda mixologist Utah has ever seen!"}, 5 {"role": "user", "content": my_prompt} 6 ], 7 response_format={ 8 "type": "json_schema", 9 "json_schema": { 10 "name": "drink_response", 11 "strict": True, 12 "schema": { 13 "type": "object", 14 "properties": { 15 "seasonal_drinks": { 16 "type": "array", 17 "items": { 18 "type": "object", 19 "properties": { 20 "drink": {"type": "string"}, 21 "reason": {"type": "string"} 22 }, 23 "required": ["drink", "reason"], 24 "additionalProperties": False 25 } 26 } 27 }, 28 "required": ["seasonal_drinks"], 29 "additionalProperties": False 30 } 31 } 32 } 33 )
Agora, vamos imprimi-lo e ver nossa resposta estruturada:
1 print(json.dumps(response.model_dump(), indent=2))
Aqui, podemos ver que a saída que procuramos está localizada dentro da parte "content " para nossas bebidas de queda. Vamos extraí-lo para ver uma lista das bebidas e as razões pelas quais cada bebida é melhor para cada estação. Vamos fazer isso imprimindo-o usando
model_dump
:1 content = response.model_dump()['choices'][0]['message']['content'] 2 print(content)
Ainda está em uma linha, então vamos imprimir as bebidas para que fiquem bonita:
1 parsed_drinks = json.loads(content) 2 seasonal_drinks_pretty = parsed_drinks['seasonal_drinks'] 3 print(json.dumps(seasonal_drinks_pretty, indent=2))
Agora podemos ver todas as bebidas perfeitas para cada estação no menu Swig! Vamos dar uma olhada em alguns deles.
A OpenAI acredita que o Suja SOP é perfeita para o verão, pois "a inclusão de pesseguigo torna essa bebida mais adequada para o verão, já que o pesquiso é normalmente associado ao tempo quente e às vindimas de verão". Uma ótima bebida para o queda e o inver no é o Dr. Spice: "A caneleira e o pau de caneleira são Temperos quentes normalmente associados ao queda e ao inver no, tornando esta bebida mais adequada para o tempo mais frio."
Agora que sabemos quais bebidas à base de soda são perfeitas para cada estação, com base em nossa saída, Go em frente e insira nossas bebidas como documentos em nosso cluster MongoDB Atlas para que possamos executar um pipeline de agregação nelas e descobrir quais são perfeitas para nossa próxima estação de queda.
Nosso primeiro passo é instalar o
pymongo
. PyMongo é o driver oficial do MongoDB para aplicativos Python.Instale-o usando
pip
:1 !pip install pymongo
Aqui, vamos importar nosso MongoClient, configurar nossa conexão MongoDB usando
getpass
e, em seguida, podemos nomear nosso banco de dados de dados e coleção o que quisermos, pois ele será criado quando inserirmos nossos dados. Estou nomeando meu banco de dados de dados "swig_menu " e a coleção "fall_drinks. "1 from pymongo import MongoClient 2 3 # set up your MongoDB connection 4 connection_string = getpass.getpass(prompt= "Enter connection string WITH USER + PASS here") 5 client = MongoClient(connection_string, appname = "devrel.showcase.swig_menu") 6 7 # name your database and collection anything you want since it will be created when you enter your data 8 database = client['swig_menu'] 9 collection = database['seasonal_drinks'] 10 11 # insert our fall drinks 12 collection.insert_many(seasonal_drinks_pretty)
Depois de executar este bloco, verifique se tudo foi importado corretamente:
Agora, vamos criar um índice do Atlas Search para que possamos usar a Atlas Searchdo MongoDB em nossos documentos!
Depois de criar seu índice de pesquisa, crie um pipeline de agregação usando a UI do MongoDB Atlas . Para fazer isso, vá até "Collections " e clique em "Aggregation. " Aqui, podemos pesquisar em nossas bebidas sazonais e usar o recurso de correspondência exata do Atlas Search para descobrir quais bebidas são as melhores para o queda!
Vamos primeiro ver todas as bebidas de queda que nosso modelo de AI encontrou para nós. Para fazer isso, podemos usar nosso operador
$search
e criar um estágio em nosso pipeline de agregação :1 { 2 "text": { 3 "query": "fall", 4 "path": "reason" 5 } 6 }
Temos oito resultados!
Agora, digamos que eu queira coquetéis para o fim de ano que tenham o segredo apple. Para fazer isso, precisamos usar um operadorcomposto que combine duas ou mais queries. Então, isso está mostrando que preciso encontrar bebidas que contenham "fall " E "apple. " O operador precisa ser um "must. " Se eu quisesse "fall " OU "apple, ", precisaria para usar um “should. "
1 { 2 "compound": { 3 "must": [ 4 { 5 "text": { 6 "query": "fall", 7 "path": "reason" 8 } 9 }, 10 { 11 "text": { 12 "query": "apple", 13 "path": "reason" 14 15 } 16 } 17 ], 18 } 19 }
Temos duas ótimas opções para bebidas de cairo que incluem Maçãs!
Agora, podemos encontrar bebidas no site da Swig que são superespecíficas para o que desejamos em cada estação.
Neste tutorial, examinamos como raspar um site usando o Playwright, colocamos nossas informações raspadas no OpenAI e obtemos resultados para bebidas sazonais a partir do menu com argumentos e uma saída estruturada, e finalizamos o tutorial importando nosso bebidas com suas razões no MongoDB Atlas e usei oMongoDB Atlas Search para encontrar bebidas de queda e seus componentes!
Web scraping com Playwright: https://xyLabs.io/blog/playwright-web-scraping https://www.lambdatest.com/blog/playwright-for-web-scraping/
Seletor de query com Playwright: https://playwright.dev/python/docs/api/class-page#pagequery\_selectorselector
Saídas estruturadas: https://openai.com/index/introducing-Structured-outputs-in-the-api/
Correspondências exatas no MongoDB Atlas Search: https://www.mongodb.com/developer/products/atlas/atlas-search-exact-match/
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.