-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
119 lines (100 loc) · 8.89 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import os
import pandas as pd
import requests
from bs4 import BeautifulSoup
########################################################################################################################
# ЭТО СТАРЫЙ КОД
########################################################################################################################
# icd = open('data/ICD10.csv', 'rb')
# icdvoc = pd.read_csv(icd)
# il = icdvoc['concept_code'].unique().tolist()
# # #driver = webdriver.Chrome("chromedriver.exe")
#
# k = []
# for j in il:
# # driver.request.get("https://icdlist.com/icd-10/"+j)
# s = requests.Session()
# page = s.get("https://icdlist.com/icd-10/"+j)
# # content = request.page_source
# soup = BeautifulSoup(page.content, 'html.parser')
# a = soup.find_all('section', id='Synonyms-' + j.replace('.', ''))
# for r in a:
# k.append([r.find('ul'), j])
# print(k)
# request.close()
########################################################################################################################
# ЭТО НОВЫЙ КОД
########################################################################################################################
### ВАЖНО
# я в общем проагрейдил чуток этот скрипт, чтобы он по ключу (идентификатору болезни) выводил ее синонимы
# не использую pandas, потому что, чтобы распарсить csv это прям перебор, но для дата-сатанистов это максимально
# стандартный инструмент, поэтому используйте на здоровье
import csv
# это множество, в нем не бывает дубликатов (т.е. если вы добавите дважды один и тот же элемент, то в множестве все
# равно будет только один), но важно понимать, что порядок перебора элементов в множестве не гарантирован
il = set()
# собственно наши финальные результаты
# defaultdict отличается от обычного dict тем, что при отсутствии ключа, с которым пытается взаимодейстовать код,
# он запускает функцию, указанную в первом аргументе, т.е. в данном случае при отсутствии ключа в словаре, при
# обращении к данному ключу он создаст этот ключ и в качестве значения для него пустой список(list)
from collections import defaultdict
synonyms_dict = defaultdict(list)
# использую os.path.join, потому что на винде разделителем в пути до файла является "\", а на линуксе и маке - "/"
# with в питоне - тема на отдельную лекцию, либо на копание в документации (там не сложно)
with open(os.path.join('data', 'ICD10.csv')) as csvfile:
icd = csv.reader(csvfile)
for n, row in enumerate(icd):
# т.к. в первой строке заголовки, то пропускаем их
if n == 0:
continue
# собственно формируем множество идентификаторов болезней
concept_code = row[0]
il.add(concept_code)
# # преобразуем в список из множества, аналог вызова метода .tolist() - на самом деле в текущем коде это преобразование
# лишнее, т.к. нам надо пройти по этому множеству всего один раз и неважно в каком порядке
il = list(il)
# # строки с 56 по 65 можно заменить на серию команд
# генераторное выражение, прикольная фича питона, можно взять на вооружение
# il = {row[0] for row in icd[1:]}
# # в результате в il будет генератор(стандартная сущность в питоне, главная суть которой в том, что весь набор
# # элементов не хранится в памяти, а генеририется "на ходу"). Про генератор важно знать, что пройтись по нему можно
# # только один раз в отличии от типов вроде list(список - []), set(множество - set()), dictionary(словарь- {}) и т.д.,
# # т.к. все они хранятся целиком в памяти, и по ним можно итерироваться бесконечноt кол-во раз
#
# # преобразуем в множество, чтобы исключить дубликаты, аналог строки icdvoc['concept_code'].unique()
# il = set(il)
#
# # преобразуем в список из множества, аналог вызова метода .tolist()
# il = list(il)
with requests.Session() as s:
# таким образом мы маскируемся под обычный браузер, который автоматически передает такой заголовок в http-запросе
# это я скопировал из браузера в маке на винде будет другой заголовокб ноБ в любом случае, я его скопировал из
# консоли разработчика в хроме, на вкладке Network ищем нужный запрос -> Headers -> Request headers -> User-Agent.
# Собственно так на данном ресурсе и реализована защита от ботов - путем сверки http-заголовка User-Agent.
s.headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/97.0.4692.71 Safari/537.36',
'cookie': r'_ga=GA1.2.227663684.1640797186; _gid=GA1.2.961648405.1642405512; __cf_bm=3P2wTgFcE3Nrx_ygW1m_j_G0iw1lkNcjQstEMhR41WU-1642422905-0-AahT8XITUm3SODL9zjyJ1QNtCLL2fIRcWTpD3C3gW0Rv8rAr5lUeS6F8OZX78q/nV+XsfYMMVJ/VlJTB3fRJSoaeLLi1dHf2brOO+QfwRlYn8/sgAKa2jDTU+1pJOSIICg==; _gat_gtag_UA_68384944_1=1'
}
# на самом деле хорошей практикой в данном случае является либо выбор заголовка из заранее определенных (в коде),
# а еще лучше установка этого заголовка в соответствии со значением из переменной окружения, но переменные окружения
# - это отдельная тема
# [:100] добавил чисто для того, чтобы видеть результат выполнения скрипта - обрабатывается только первые сто
# записей из файла ICD10.csv, т.к. для 500к записей он выполняется неприлично долго (больше часа).
# Чтобы обрабатывать это быстрее(параллельно), есть известный рецепт, но отдельная тема
# неприлично долгое время
for decease_id in il[:100]:
# форматированные строки - самый модный и нормальный способ как-то сформировать необходимую строку, отличающихся
# от обычных тем, что перед кавычками стоит "f", т.е. позволяет, по сути, подставить что-то в шаблон строки, а
# кроме того работает значительно быстрее, чем конкатенация строк (через "+"), а так же старые методы
# форматирования с помощью литерала % и метода .format(), да и выглядят значительно читабельнее
page_html = s.get(f"https://icdlist.com/icd-10/{decease_id}")
soup = BeautifulSoup(page_html.content, 'html.parser')
parent_ul_element = soup.find('section',
id=f"Synonyms-{decease_id.replace('.', '')}")
if parent_ul_element:
ul_element = parent_ul_element.find('ul')
for li_element in ul_element.contents:
synonyms_dict[decease_id].append(li_element.text)
for k, v in synonyms_dict.items():
print(f"{k}: {v}")