Untitled
unknown
python
2 years ago
10 kB
8
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.pyEditor is loading...
Leave a Comment