Верстакфорум практиков
рекламаiprazon: приватные серверные адреса IPv4 и SOCKS5, безлимитный трафик, бесплатный тест до 2 часов
ФорумНовичкам

Первый скрипт: пять ошибок, которые делают все

skript_kid
skript_kid
Новичок
сообщений 54
с сен, второй сезон
22 апреля, 17:27первое сообщение

написал первый скрипт, собирает заголовки с полусотни страниц. работает, но как-то стыдно его показывать, чувствую что там всё криво

import requests

urls = open("spisok.txt").read().split("\n") for u in urls: try: r = requests.get(u) t = r.text.split("<title>")[1].split("</title>")[0] print(u, t) except: print("oshibka") ```

вчера запустил, к утру он висел на каком-то адресе и ничего не делал. разберите пожалуйста, хочу понять что тут не так

МаринаК
МаринаК
Знаток
сообщений 1120
с мая
1 сентября, 08:44#2

Показывать не стыдно, скрипт рабочий и читается. Про зависание отвечу сразу: у запроса нет ограничения по времени.

Без него библиотека готова ждать ответа сколько угодно. Сайт открыл соединение, замолчал и держит, а вы стоите до утра.

r = requests.get(u, timeout=20)

Одна правка, и ночного зависания больше не будет. Это ошибка номер один у всех без исключения.

Сева Дроздов
Сева Дроздов
Участник
сообщений 430
с сен
8 февраля, 11:01#3

Вторая прямо под ней: except без указания, что ловим.

Такая запись глотает вообще всё, включая ваше собственное нажатие на прерывание и опечатку в имени переменной. Скрипт при этом бодро печатает «oshibka» и едет дальше, а вы потом гадаете, что случилось на сорока адресах из пятидесяти.

skript_kid
skript_kid
Новичок
сообщений 54
с сен, второй сезон
15 июля, 14:18#4
Сева Дроздов: except без указания, что ловим

а что тогда ловить? я думал так надёжнее, чтобы вообще не падало

ferrum
ferrum
Участник
сообщений 660
с сен
22 декабря, 17:35#5

Ловить надо то, что вы готовы пережить, остальное пусть падает громко. Падение с понятным текстом лучше тихой строчки «oshibka», по которой нельзя восстановить, что произошло.

Разберу ваш кусок по всем пяти пунктам сразу, чтобы не растягивать.

Первое, про время ожидания, Марина уже написала. Второе: ловите отдельные виды ошибок и печатайте текст самой ошибки целиком. Третье: печать в консоль пропадает вместе с окном терминала, ночному прогону нужен файл. Четвёртое: результат должен ложиться на диск по ходу дела, иначе падение на сорок девятом адресе уносит всю работу. Пятое: разбор заголовка через нарезку строк развалится на первой же странице, где тег написан с пробелом внутри.

Вот тот же скрипт с учётом всего перечисленного:

import logging, time, random, requests
from lxml import html as lh

logging.basicConfig(filename="progon.log", level=logging.INFO, format="%(asctime)s %(message)s")

with open("spisok.txt", encoding="utf-8") as f: adresa = [s.strip() for s in f if s.strip()]

with open("vyhod.tsv", "a", encoding="utf-8") as out: for u in adresa: try: r = requests.get(u, timeout=20) zagolovok = lh.document_fromstring(r.content).findtext(".//title") or "" out.write("%s\t%s\n" % (u, zagolovok.strip())) out.flush() logging.info("ok %s %s", r.status_code, u) except requests.RequestException as e: logging.warning("set %s %s", u, e) time.sleep(random.uniform(1.0, 3.0)) ```

Обратите внимание на flush после записи и на паузу с разбросом в конце. Обе строчки короткие, обе снимают по классу проблем.

kolyan_86
kolyan_86
Участник
сообщений 640
с июл
1 мая, 08:52#6

шестую добавлю от себя: пути и имена файлов у вас прибиты внутри кода. перенесёте скрипт на сервер, и он полезет искать spisok.txt в домашней папке

МаринаК
МаринаК
Знаток
сообщений 1120
с мая
8 октября, 11:09#7

kolyan_86 дело говорит, только новичку с этого начинать рано. Сначала пусть скрипт переживёт ночь, потом уже переезды.

Про журнал добавлю одну мелочь, которую видно только на длинных прогонах. Пишите в него не только ошибки, но и удачные обращения с кодом ответа. Когда наутро выгрузка окажется наполовину пустой, вы по журналу сразу увидите, сайт молчал или разбор промахнулся. По одним ошибкам это не читается никак.

skript_kid
skript_kid
Новичок
сообщений 54
с сен, второй сезон
15 марта, 14:26#8

переписал по вашему образцу, запустил на полусотне

$ wc -l vyhod.tsv
50 vyhod.tsv
$ grep -c "set " progon.log
3

три штуки отвалились по времени ожидания, остальные на месте. заголовки теперь берутся через lxml, там на двух страницах и правда тег был с пробелом

netmon
netmon
Знаток
сообщений 1350
с мая
22 августа, 17:43#9

Раз три адреса отвалились по времени, добавьте повтор. Только сразу с растущей паузой: подряд молотить один и тот же упавший адрес смысла нет.

for popytka in range(3):
    try:
        r = requests.get(u, timeout=20)
        break
    except requests.RequestException:
        if popytka == 2:
            raise
        time.sleep(2 ** popytka + random.random())

Три попытки с паузой в одну, две, четыре секунды забирают почти все временные сбои.

Сева Дроздов
Сева Дроздов
Участник
сообщений 430
с сен
1 января, 08:00#10

И про продолжение с места остановки подумайте заранее. Проще всего дописывать пройденные адреса в отдельный файл и на старте вычитать их из списка, три строчки кода.

ferrum
ferrum
Участник
сообщений 660
с сен
8 июня, 11:17#11

Плюс к Севе. На полусотне адресов это баловство, на десяти тысячах вы без такого файла никогда не доведёте прогон до конца.

skript_kid
skript_kid
Новичок
сообщений 54
с сен, второй сезон
15 ноября, 14:34#12

собрал всё вместе: время ожидания, отдельные виды ошибок, журнал с кодами, запись построчно, разбор через lxml, повторы с растущей паузой и файл с пройденными адресами.

прогнал восемьсот адресов, прошло за сорок минут, в журнале одиннадцать повторов и ни одной потери. ночью висеть перестал.

спасибо всем, кто разобрал по пунктам. пойду теперь читать про потоки, но это уже в другую тему