Untitled
unknown
python
a year ago
10 kB
3
Indexable
import base64 import hashlib import re from threading import Thread from threading import Lock import subprocess,time from random import randint from random import randrange import os import socket import MySQLdb import urllib.parse proxy_type = 'http' #socks5, http if proxy_type == 'http': import requests else: import requesocks as requests num_threads = 10 myLock = Lock() #mysql myLock2 = Lock() #schetchiki i = 0 con = MySQLdb.connect(host="localhost", user="root", passwd="", db="wiki") cur = con.cursor() cur.execute('SET NAMES `utf8`') con.autocommit(True) #Так как я остановил предыдущий скрипт, то в базе могут остатьс записи со статусом inprogress, делаем их pending cur.execute("UPDATE `wikipedia` SET status = 'pending' WHERE status='inprogress'") def parse(): global con global cur global myLock global i while True: myLock.acquire() try: #по умолчанию новые добавляемые записи в таблице имеют статус pending, это значит те которые нужно просканировать #всего три статуса pending, inprogress, done #берем одну запись со статусом pending cur.execute("SELECT id, url FROM `wikipedia` WHERE status = 'pending' AND lang = 'ru' LIMIT 1") except: pass result = cur.fetchall() if result: try: #так как программа многопоточна, то другой поток может взять в работу эту же запись в базе #чтобы такого не было, помечаем запись как inprogress cur.execute("UPDATE `wikipedia` SET status = 'inprogress' WHERE id=" + str(result[0][0])) except: pass myLock.release() if result: #если есть задача хотябы одна, то начинаем ее выполнять #получаем хтмл код вики страницы html = file_get_contents(result[0][1]) #парсим все ссылки на странице (в HTML коде) links = parse_links(result[0][1], html) #в переменно links находятся все ссылки из HTML кода, перебираем их в цикле for link in links: #регулярными выражениями проверяем является ссылка внешней или внутренней #если ссылка содержит wikipedia.org то она внутренняя, иначе - внешняя p = re.compile("https:\/\/[^\/]*wikipedia.org") m = p.search(link) if m: #ссылка является внутренней #определяем язык внутренней ссылки википедии # например функция вернет ru для ссылки https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0 # то есть ru это то что находится между 'https://' и 'wikipedia.org' lang = get_lang_wiki(link) myLock.acquire() try: #провеярем есть ли эта внутренняя ссылка в базе cur.execute("SELECT id FROM `wikipedia` WHERE url = '" + con.escape_string.decode("utf-8")(link) + "'") except: pass result2 = cur.fetchall() if not result2: try: #если такой ссылки нет в базе, то заносим ее в базу #указывая url и lang, кстати поле status проставится pending по умолчанию #можно так базу проектировать чтобы при добавлении новых записей поле имело значение по умолчанию #напомню pending - это означает что задачу нужно сделать, а done что задача сделана #то есть все добавляемые новые ссылки со статусом pending (нужно сделать) cur.execute("INSERT INTO `wikipedia` (`url`, `lang`) VALUES ('" + con.escape_string(link).decode("utf-8") + "', '" + lang + "')") except: pass myLock.release() else: #ссылка является внешней # определяем зону домена # Функция принимает на вход ссылку, наример https://www.bing.com/maps/default.aspx # и возвращает доменную зону com zone = get_zone(link) myLock.acquire() try: #вставляем в базу внешнюю ссылку cur.execute("INSERT INTO `links` (`wikipedia_id`, `url`, `zone`) VALUES (" + str(result[0][0]) + ", '" + con.escape_string(link).decode("utf-8") + "', '" + zone + "')") except: pass myLock.release() myLock.acquire() try: #мы закончили выполнять текущую задачу, помечаем ее как done cur.execute("UPDATE `wikipedia` SET status = 'done' WHERE id=" + str(result[0][0])) except: pass myLock.release() myLock2.acquire() i += 1 myLock2.release() else: #если задач в базе нет, то спим 5 секунд, и через 5 секунд проверяем снова есть ли задачи time.sleep(5) #функция принимает на вход урл, например https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0 #т возвращет HTML код этой страницы def file_get_contents(url): html = '' try: headers = { 'User-Agent': "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", 'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", 'Accept-Language': "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3", } session = requests.Session() response = session.post(url, headers=headers, allow_redirects=True, timeout=5) html = response.text except: pass return html #Функция принимает на вход HTML код и возвращает все ссылки на этой странице (внутренние и внешние) def parse_links(base_url, html): p = re.compile("<a[^>]+href=('|\")([^'\"]+)('|\")") links = re.findall(p, html) absolute_links = [] for link in links: absolute_links.append(urllib.parse.urljoin(base_url, link[1])) return absolute_links #функция возвращает язык внутренней страницы википедии #например функция вернет ru для ссылки https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0 #то есть ru это то что находится между 'https://' и 'wikipedia.org' def get_lang_wiki(link): lang = 'en' m = re.search('https:\/\/([^\.]+)\.wikipedia.org', link) if m: lang = m.group(1) return lang #определяем зону домена #Функция принимает на вход ссылку, наример https://www.bing.com/maps/default.aspx #и возвращает доменную зону com def get_zone(link): m = re.search('https?:\/\/[^\/]+\.([a-z]+)', link) if m: return m.group(1) else: return '' def showstat(): global con global cur global myLock global i while True: myLock.acquire() try: #Достань кол-во записей в таблице wikipedia у которых статус done (выполнены) cur.execute("SELECT COUNT(*) FROM `wikipedia` WHERE status='done'") except: pass result_wikipedia_done = cur.fetchall() try: #Достань кол-во записей в таблице wikipedia cur.execute("SELECT COUNT(*) FROM `wikipedia`") except: pass result_wikipedia = cur.fetchall() try: # Достань кол-во записей в таблице links cur.execute("SELECT COUNT(*) FROM `links`") except: pass result_links = cur.fetchall() myLock.release() print("position: " + str(i) + ", wikipedia done: " + str(result_wikipedia_done[0][0]) + ", wikipedia total: " + str(result_wikipedia[0][0]) + ", links: " + str(result_links[0][0])) time.sleep(5) worker1 = Thread(target=showstat) worker1.daemon = True worker1.start() for i in range(num_threads): worker = Thread(target=parse) worker.daemon = True worker.start() worker.join() worker1.join() #c:\Python311\python d:\python\wiki\main.py
Editor is loading...
Leave a Comment