GOOGLE ADS

среда, 13 апреля 2022 г.

Использование scrapy для очистки нескольких страниц и нескольких URL-адресов

Ранее я выполнял небольшой проект по очистке веб-сайта недвижимости с помощью BeautifulSoup, но сбор около 5000 точек данных занял много времени. Я думал об изучении многопоточной обработки и реализации ее с помощью BS, но кто-то сообщил мне, что веб-сканирование с помощью Scrapy может быть быстрее и проще. Кроме того, я переключился с использования Spyder на Pycharm в качестве своей IDE. Это все еще неприятный опыт, но я пытаюсь привыкнуть к этому.

Однажды я просмотрел документацию и выполнил несколько примеров очистки с помощью Scrapy, но все еще испытываю трудности. Я планировал использовать свой ранее созданный скрипт парсинга BS в качестве основы и создать новый проект Scrapy для веб-скрейпинга данных о недвижимости. Однако я не знаю, как и с чего начать. Любая помощь очень ценится. Спасибо.

Желаемый результат:
очистить несколько страниц с нескольких URL-адресов с помощью Scrapy. Очистите несколько значений, введя ссылки на список квартир и получив данные от каждого.

Сценарий Scrapy (пока):

# -*- coding: utf-8 -*-
# Import library
import scrapy
# Create Spider class
class UneguiApartmentSpider(scrapy.Spider):
name = 'apartments'
allowed_domains = ['www.unegui.mn']
start_urls = [
'https://www.unegui.mn/l-hdlh/l-hdlh-zarna/oron-suuts-zarna/'
]
# headers
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
}
def parse(self, response):
for listings in response.xpath("//div[@class='list-announcement']"):
item = ApartmentsItem()
item['name'] = listings.xpath('text()').extract()
item['link'] = listings.xpath('href').extract()
yield item

Скрипт BeautifulSoup:

В этом скрипте все еще есть некоторые проблемы, которые я пытаюсь решить, такие как очистка города и цены. Например, для URL-адреса квартир с 4 спальнями (/4-r/) создается ошибка или пустое значение, поскольку есть списки VIP.

# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup as BS
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from timeit import default_timer as timer
import pandas as pd
import re
import csv
dt_today = datetime.today()
date_today = dt_today.strftime('%Y-%m-%d')
date_today2 = dt_today.strftime('%Y%m%d')
date_yesterday = (dt_today-relativedelta(day=1)).strftime('%Y-%m-%d')
def main():
page = 0
name = []
date = []
address = []
district = []
city = []
price = []
area_sqm = []
rooms = []
floor = []
commission_year = []
building_floors = []
garage = []
balcony = []
windows = []
window_type = []
floor_type = []
door_type = []
leasing = []
description = []
link = []

for i in range (5,6):
BASE = 'https://www.unegui.mn'
URL = f'{BASE}/l-hdlh/l-hdlh-zarna/oron-suuts-zarna/{i}-r/?page='
COLUMNS=['Name','Date','Address','District','City','Price','Area_sqm','Rooms','Floor','Commission_year',
'Building_floors','Garage', 'Balcony','Windows','Window_type','Floor_type','door_type','Leasing','Description','Link']

with requests.Session() as session:
while True:
(r:= session.get(f'{URL}{page+1}')).raise_for_status()
m = re.search('.*page=(\d+)$', r.url)
if m and int(m.group(1)) == page:
break
page += 1
start = timer()
print(f'Scraping {i} bedroom apartments page {page}')

soup = BS(r.text, 'lxml')
for tag in soup.findAll('div', class_='list-announcement-block'):
_name = tag.find('a', attrs={'itemprop': 'name'})
name.append(_name.get('content', 'N/A'))
if (_link:= _name.get('href', None)):
link.append(f'{BASE}{_link}')
(_r:= session.get(link[-1])).raise_for_status()
_spanlist = BS(_r.text, 'lxml').find_all('span', class_='value-chars')
floor_type.append(_spanlist[0].get_text().strip())
balcony.append(_spanlist[1].get_text().strip())
garage.append(_spanlist[2].get_text().strip())
window_type.append(_spanlist[3].get_text().strip())
door_type.append(_spanlist[4].get_text().strip())
windows.append(_spanlist[5].get_text().strip())

_alist = BS(_r.text, 'lxml').find_all('a', class_='value-chars')
commission_year.append(_alist[0].get_text().strip())
building_floors.append(_alist[1].get_text().strip())
area_sqm.append(_alist[2].get_text().strip())
floor.append(_alist[3].get_text().strip())
leasing.append(_alist[4].get_text().strip())
district.append(_alist[5].get_text().strip())
address.append(_alist[6].get_text().strip())

rooms.append(tag.find('div', attrs={'announcement-block__breadcrumbs'}).get_text().split('»')[1].strip())
description.append(tag.find('div', class_='announcement-block__description').get_text().strip())
date.append(tag.find('div', class_='announcement-block__date').get_text().split(',')[0].strip())
city.append(tag.find('div', class_='announcement-block__date').get_text().split(',')[1].strip())
# if ( _price:= tag.find('div', class_='announcement-block__price _premium')) is None:
# _price = tag.find('meta', attrs={'itemprop': 'price'})['content']

# price.append(_price)
end = timer()
print(timedelta(seconds=end-start))

df = pd.DataFrame(zip(name, date, address, district, city,
price, area_sqm, rooms, floor, commission_year,
building_floors, garage, balcony, windows, window_type,
floor_type, door_type, leasing, description, link), columns=COLUMNS)
return(df)

df['Date'] = df['Date'].replace('Өнөөдөр', date_today)
df['Date'] = df['Date'].replace('Өчигдөр', date_yesterday)
df['Area_sqm'] = df['Area_sqm'].replace('м²', '')
df['Balcony'] = df['Balcony'].replace('тагттай', '')
if __name__ == '__main__':
df = main()
df.to_csv(f'{date_today2}HPD.csv', index=False)


Решение проблемы

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

import scrapy
class spiders(scrapy.Spider):
name = "try"
start_urls = ["https://www.amazon.sg/gp/bestsellers/baby/ref=zg_bs_nav_0",'https://www.amazon.sg/gp/browse.html?node=6537678051&ref_=nav_em__home_appliances_0_2_4_4']
def parse(self, response):
for url in response.css('.mr-directory-item a::attr(href)').getall(): #loop for each href
yield scrapy.Request(f'https://muckrack.com{url}', callback=self.parse_products,
dont_filter=True)
def parse_products(self, response):
#these are for another website
full_name = response.css('.mr-font-family-2.top-none::text').get()
Media_outlet = response.css('.mr-person-job-item a::text').get()

yield {'Full Name': full_name, 'Media outlet':Media_outlet,'URL': response.url}

если вы хотите выполнять разные процессы для каждого URL-адреса, который вы должны использовать

import scrapy
class spiders(scrapy.Spider):
name = "try"
def start_requests(self):
yield scrapy.Request('url1',callback=self.parse1)
yield scrapy.Request('url2',callback=self.parse2)
def parse1(self, response):
for url in response.css('.mr-directory-item a::attr(href)').getall():#loop for each href
yield scrapy.Request(f'https://muckrack.com{url}', callback=self.parse_products,
dont_filter=True)
def parse2(self, response):
for url in response.css('.mr-directory-item a::attr(href)').getall():#loop for each href
yield scrapy.Request(f'https://muckrack.com{url}', callback=self.parse_products,
dont_filter=True)
def parse_products(self, response):
#these are for another website
full_name = response.css('.mr-font-family-2.top-none::text').get()
Media_outlet = response.css('.mr-person-job-item a::text').get()
#yield {'header':'data'}
yield {'Full Name': full_name, 'Media outlet':Media_outlet,'URL': response.url}```

Комментариев нет:

Отправить комментарий

Laravel Datatable addColumn returns ID of one record only

Я пытаюсь использовать Yajra Datatable для интеграции DataTable на свой веб-сайт. Я смог отобразить таблицу, но столкнулся с проблемой. В по...