Есть у меня код, который выводит парсер с сайта РФФИ. Сам парсер должен быть выведен в JSON и выглядеть следующим образом:
{
"Название"
"Статус"
"Время окончания приема заявок"
"Полное описание условий конкурса"
"Документы" {
"Формы заявок"
"Договор и инструкции"
"Формы отчетов"
}
}
import requests
import json
from bs4 import BeautifulSoup
import chardet
import xlsxwriter
import re
from datetime import date, timedelta
PAGES_COUNT = 100
OUT_FILENAME = 'out.json'
import warnings
warnings.filterwarnings("ignore")
def get_soup(url, **kwargs):
response = requests.get(url, **kwargs, verify=False)
if response.status_code == 200:
soup = BeautifulSoup(response.text, features='html.parser')
else:
soup = None
return soup
def crawl_products(pages_count):
urls = []
fmt = 'https://www.rfbr.ru/rffi/ru/contest?CONTEST_STATUS_ID=-1&CONTEST_TYPE=-1&CONTEST_YEAR=-1&page={page}'
for page_n in range(1, 1 + pages_count):
print('page: {}'.format(page_n))
page_url = fmt.format(page=page_n)
soup = get_soup(page_url)
if soup is None:
break
for tag in soup.select('.tr .link'):
href = tag.attrs['href']
url = 'https://www.rfbr.ru/rffi/ru/contest{}'.format(href)
urls.append(url)
return urls
def parse_products(urls):
data = []
for url in urls:
print('product: {}'.format(url))
soup = get_soup(url)
if soup is None:
break
for i in soup.find_all("h1"):
name = i.text
for j in soup.find_all("main", {"class":"template__main"}):
for jj in j.find_all("div", {"class":"sfc l-3 mt-5 mb-10 lh-xl"}):
ja = re.sub(r'[^\x00-\x7f]', r'', str(jj))
jo = re.sub(r'\<[^>]*\>', '', str(ja))
ji = re.sub(r'_', '', str(jo))
ju = re.sub(r' ', '', str(ji))
je = re.sub(r' :', '', str(ju))
jy = je[13:]
amount = jy
rponse = requests.get(url, verify=False)
sp = BeautifulSoup(rponse.text, "lxml")
document ={}
dcs = sp(attrs={"class": "list-in article"})
for z in dcs:
document[z.h2.text] = list(z.ol.stripped_strings)
# document[z.h2.text] = tuple(z.ol.stripped_strings)
# в одну строку с разделителем запятая
for z in dcs:
document[z.h2.text] = ', '.join(z.ol.stripped_strings)
try:
article = [l.get_text(strip=True) for l in soup.find_all("p") if l.get_text(strip=True).startswith('Условия')]
art = str(article).replace("['", '').replace("']", '')
except:
article = [l.get_text(strip=True) for l in soup.find_all("strong") if l.get_text(strip=True).startswith('Условия')]
art = str(article).replace("['", '').replace("']", '')
for row in soup.select('td'):
cols = row.select('td')
cols = [c.text.strip() for c in cols]
item = {
'Название': name,
'Статус': 'Заявки не принимаются',
'Время окончания приема заявок': amount,
'Полное описание условий конкурса': art
}
item['Документы'] = document
data.append(item)
return data
def dump_to_json(filename, data, **kwargs):
kwargs.setdefault('ensure_ascii', False)
kwargs.setdefault('indent', 1)
with open(OUT_FILENAME, 'w') as f:
json.dump(data, f, **kwargs)
def main():
urls = crawl_products(PAGES_COUNT)
data = parse_products(urls)
dump_to_json(OUT_FILENAME, data)
with open(OUT_FILENAME, 'w') as f:
json.dump(data, f, ensure_ascii=False, indent=1)
if __name__ == '__main__':
main()
Или вот ещё вариант:
import requests
import json
from bs4 import BeautifulSoup
import chardet
import xlsxwriter
import re
from datetime import date, timedelta
PAGES_COUNT = 100
OUT_FILENAME = 'out.json'
import warnings
warnings.filterwarnings("ignore")
def get_soup(url, **kwargs):
response = requests.get(url, **kwargs, verify=False)
if response.status_code == 200:
soup = BeautifulSoup(response.text, features='html.parser')
else:
soup = None
return soup
def crawl_products(pages_count):
urls = []
fmt = 'https://www.rfbr.ru/rffi/ru/contest?CONTEST_STATUS_ID=-1&CONTEST_TYPE=-1&CONTEST_YEAR=-1&page={page}'
for page_n in range(1, 1 + pages_count):
print('page: {}'.format(page_n))
page_url = fmt.format(page=page_n)
soup = get_soup(page_url)
if soup is None:
break
for tag in soup.select('.tr .link'):
href = tag.attrs['href']
url = 'https://www.rfbr.ru/rffi/ru/contest{}'.format(href)
urls.append(url)
return urls
def parse_products(urls):
data = []
for url in urls:
print('product: {}'.format(url))
soup = get_soup(url)
if soup is None:
break
for i in soup.find_all("h1"):
name = i.text
for j in soup.find_all("main", {"class":"template__main"}):
for jj in j.find_all("div", {"class":"sfc l-3 mt-5 mb-10 lh-xl"}):
ja = re.sub(r'[^\x00-\x7f]', r'', str(jj))
jo = re.sub(r'\<[^>]*\>', '', str(ja))
ji = re.sub(r'_', '', str(jo))
ju = re.sub(r' ', '', str(ji))
je = re.sub(r' :', '', str(ju))
jy = je[13:]
amount = jy
rponse = requests.get(url, verify=False)
sp = BeautifulSoup(rponse.text, "lxml")
document ={}
dcs = sp(attrs={"class": "list-in article"})
for z in dcs:
document[z.h2.text] = list(z.ol.stripped_strings)
# document[z.h2.text] = tuple(z.ol.stripped_strings)
# в одну строку с разделителем запятая
for z in dcs:
document[z.h2.text] = ', '.join(z.ol.stripped_strings)
article = [l.get_text(strip=True) for l in soup.find_all("p") if l.get_text(strip=True).startswith('Условия')]
art = str(article).replace("['", '').replace("']", '')
for row in soup.select('td'):
cols = row.select('td')
cols = [c.text.strip() for c in cols]
item = {
'Название': name,
'Статус': 'Заявки не принимаются',
'Время окончания приема заявок': amount,
'Полное описание условий конкурса': art
}
item['Документы'] = document
data.append(item)
return data
def dump_to_json(filename, data, **kwargs):
kwargs.setdefault('ensure_ascii', False)
kwargs.setdefault('indent', 1)
with open(OUT_FILENAME, 'w') as f:
json.dump(data, f, **kwargs)
def main():
urls = crawl_products(PAGES_COUNT)
data = parse_products(urls)
dump_to_json(OUT_FILENAME, data)
with open(OUT_FILENAME, 'w') as f:
json.dump(data, f, ensure_ascii=False, indent=1)
if __name__ == '__main__':
main()
Код работает. И всё бы ничего. Но тут есть нюанс.
Нужно, чтобы в одном из массивов выводилось предложение со слов "Условия конкурса". Оно выводится. Но не из всех ссылок.
Что и где нужно исправить? Я если что не прошу, чтобы за меня написали код. Я это могу сделать сам. Просто дайте подсказку.