Iteradores de transmisión de respuesta

El método search_stream devuelve un iterador de SearchGoogleAdsStreamResponse objetos.

Itera a través de las respuestas de transmisión

Puedes iterar a través de cada GoogleAdsRow en el campo results de cada respuesta, como se muestra en el siguiente ejemplo de código:

def main(client: GoogleAdsClient, customer_id: str) -> None:
    ga_service: GoogleAdsServiceClient = client.get_service("GoogleAdsService")

    query: str = """
        SELECT
          campaign.id,
          campaign.name
        FROM campaign
        ORDER BY campaign.id"""

    # Issues a search request using streaming.
    stream: Iterator[SearchGoogleAdsStreamResponse] = ga_service.search_stream(
        customer_id=customer_id, query=query
    )

    for batch in stream:
        rows: List[GoogleAdsRow] = batch.results
        for row in rows:
            print(
                f"Campaign with ID {row.campaign.id} and name "
                f'"{row.campaign.name}" was found.'
            )
      

La estructura de cada GoogleAdsRow está determinada por los campos que seleccionas en tu consulta del lenguaje de consultas de Google Ads (GAQL). Para obtener más detalles sobre la estructura de la respuesta, consulta Lenguaje de consultas de Google Ads.

Mantén el iterador dentro del alcance

Cuando se llama a GoogleAdsService.search_stream, se devuelve un iterador de respuesta de transmisión. Este iterador debe permanecer en el mismo alcance que el cliente GoogleAdsService mientras se consume para evitar transmisiones interrumpidas o errores de segmentación. Esto se debe a que el objeto Channel de gRPC subyacente se recopila como elemento no utilizado una vez que el objeto GoogleAdsService abierto queda fuera del alcance. Si el objeto GoogleAdsService ya no está dentro del alcance cuando se produce la iteración en el resultado de search_stream, es posible que el objeto Channel ya se haya destruido, lo que provoca un comportamiento indefinido cuando el iterador intenta recuperar el siguiente valor.

En el siguiente código, se muestra el uso incorrecto de los iteradores de transmisión:

def stream_response(client, customer_id, query):
    # The GoogleAdsService instance goes out of scope when this function
    # returns.
    ga_service = client.get_service(
        "GoogleAdsService", version="v26"
    )
    return ga_service.search_stream(customer_id=customer_id, query=query)


def main(client, customer_id):
    query = "SELECT campaign.name FROM campaign LIMIT 10"
    response = stream_response(client, customer_id, query=query)

    # Accessing the iterator in a different scope from where the service object
    # was created results in undefined behavior.
    for batch in response:
        print(batch)

En este código, el objeto GoogleAdsService se crea dentro de un alcance diferente de donde se accede al iterador. Como resultado, es posible que el objeto Channel se destruya antes de que el iterador consuma toda la respuesta.

En su lugar, mantén el iterador de transmisión en el mismo alcance que el cliente GoogleAdsService durante el tiempo que se use:

def main(client, customer_id):
    ga_service = client.get_service(
        "GoogleAdsService", version="v26"
    )
    query = "SELECT campaign.name FROM campaign LIMIT 10"
    response = ga_service.search_stream(customer_id=customer_id, query=query)

    # Access the iterator in the same scope where the service object was
    # created.
    for batch in response:
        print(batch)