Если вы используете Selenium
для чтения страницы, то вы также можете использовать Selenium
для поиска элементов на странице.
Некоторые элементы не имеют companytext
, поэтому, если вы получаете отдельно companytext
и Отдельно address
/ phone
тогда вы можете создать неправильные пары: (second name, first phone, first address)
, (third name, second phone, second address)
, et c. Лучше найти элемент, который группирует name
, phone
, address
, а затем искать name
, phone
, address
внутри этого элемента - если он не может найти имя, тогда вы должны поставить пустое имя или выполнить поиск другой элемент с именем внутри этой группы. Я обнаружил, что некоторые элементы отображают изображение с lo go вместо имени и имеют имя в <img alt="...">
Не очень хорошая идея записывать данные CSV в файл, используя стандарт write()
, потому что address
может иметь много ,
, и это может создать много столбцов. При использовании модуля csv
адрес будет помещен в " "
в виде одного столбца.
from selenium import webdriver
import csv
MAX_PAGE_NUM = 5
#driver = webdriver.Chrome()
driver = webdriver.Firefox()
with open('results.csv', 'w') as f:
csv_writer = csv.writer(f)
csv_writer.writerow(["Bussiness Name", "Phone Number", "Address"])
for page_num in range(1, MAX_PAGE_NUM+1):
#page_num = '{:03}'.format(page_num)
url = 'https://www.yellowpages.my/listing/results.php?keyword=boutique&where=selangor&screen={}'.format(page_num)
driver.get(url)
for item in driver.find_elements_by_xpath('//div[@id="content_listView"]//li'):
try:
name = item.find_element_by_xpath('.//div[@class="cbp-vm-companytext"]').text
except Exception as ex:
#print('ex:', ex)
name = item.find_element_by_xpath('.//a[@class="cbp-vm-image"]/img').get_attribute('alt')
phone = item.find_element_by_xpath('.//div[@class="cbp-vm-cta"]//span[@data-original-title="Phone"]').get_attribute('data-content')
phone = phone[:-4].split(">")[-1]
address = item.find_element_by_xpath('.//div[@class="cbp-vm-address"]').text
address = address.split('\n')[-1]
print(name, '|', phone, '|', address)
csv_writer.writerow([name, phone, address])
Кстати: вам не нужно преобразовывать номер страницы в три цифры - ie. 001
- работает также с 1
. Но если вы хотите конвертировать, используйте форматирование строки
page_num = '{:03}'.format(i)
Это можно сделать также только с requests
и BeautifulSoup
без Selenium
.
Если у вас есть чтобы получить HTML из Selenium
, тогда у вас есть driver.page_source
- но driver.get()
нужно url
, и тогда вам не нужно requests
для этого.
driver.get(url)
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
РЕДАКТИРОВАТЬ: Я могу получить его с requests
и BeautifulSoup
без Selenium
, только если я использую "lxml"
вместо "html.parser"
. Кажется, в HTML есть некоторые ошибки, и "html.parser"
имеет проблему, чтобы правильно разобрать его
import requests
from bs4 import BeautifulSoup as BS
import csv
#import webbrowser
MAX_PAGE_NUM = 5
#headers = {
# "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0"
#}
with open('results.csv', 'w') as f:
csv_writer = csv.writer(f)
csv_writer.writerow(["Bussiness Name", "Phone Number", "Address"])
for page_num in range(1, MAX_PAGE_NUM+1):
#page_num = '{:03}'.format(page_num)
url = 'https://www.yellowpages.my/listing/results.php?keyword=boutique&where=selangor&screen={}'.format(page_num)
response = requests.get(url) #, headers=headers)
soup = BS(response.text, 'lxml')
#soup = BS(response.text, 'html.parser')
#with open('temp.html', 'w') as fh:
# fh.write(response.text)
#webbrowser.open('temp.html')
#all_items = soup.find('div', {'id': 'content_listView'}).find_all('li')
#print('len:', len(all_items))
#for item in all_items:
for item in soup.find('div', {'id': 'content_listView'}).find_all('li'):
try:
name = item.find('div', {'class': 'cbp-vm-companytext'}).text
except Exception as ex:
#print('ex:', ex)
name = item.find('a', {'class': 'cbp-vm-image'}).find('img')['alt']
phone = item.find('div', {'class': 'cbp-vm-cta'}).find('span', {'data-original-title': 'Phone'})['data-content']
phone = phone[:-4].split(">")[-1].strip()
address = item.find('div', {'class': 'cbp-vm-address'}).text
address = address.split('\n')[-1].strip()
print(name, '|', phone, '|', address)
csv_writer.writerow([name, phone, address])