2015-03-04 1 views
1

Это следующий вопрос к моему предыдущему вопросу о переходе через несколько веб-страниц. Я новичок в программировании ... поэтому я ценю ваше терпение и очень явные объяснения!Запись CSV-файла при циклическом перемещении по веб-страницам

Я запрограммировал цикл через многие веб-страницы. На каждой странице я хочу скопировать данные, сохранить их в переменную или файл csv (в зависимости от того, что проще/стабильнее), затем нажмите кнопку «Далее», скопируйте данные на второй странице и добавьте их в переменную или CSV файлов и т.д.

в частности, мой код выглядит следующим образом:

url="http://www.url.com" 
driver = webdriver.Firefox() 
driver.get(url) 
(driver.page_source).encode('utf-8') 
html = urllib.request.urlopen(url).read() 
soup = BeautifulSoup(html) 

wait = WebDriverWait(driver, 10) 

while True: 
    # some code to grab the data 
    job_tag={'class': re.compile("job_title")} 
    all_jobs=soup.findAll(attrs=job_tag) 
    jobs=[] 
    for text in (all_jobs): 
    t=str(''.join(text.findAll(text=True)).strip()) 
    jobs.append(t) 

    writer=csv.writer(open('test.csv','a', newline='')) 
    writer.writerows(jobs) 

    # click next link 
    try: 
     element=wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id='reviews']/a/span[starts-with(.,'Next')]"))) 
     element.click() 
    except TimeoutException: 
     break 

Он работает без ошибок, но 1) файл собирает данные первой страницы снова и снова, но не данные последующих страниц, даже если цикл работает правильно (в конечном счете, я не имею в виду дубликаты записей, но мне нужны данные со всех страниц). Я подозреваю, что мне нужно «переопределить» суп для каждой новой страницы, я изучаю, как сделать bs4 доступ к этим URL-адресам.

2) на последней странице отсутствует «следующая» кнопка, поэтому код не добавляет данные последней страницы (я получаю эту ошибку, когда использую «w» вместо «a» в строке csv, с данными запись второй страницы в файл csv).

Кроме того, хотя это небольшая проблема, данные записываются по одной букве на ячейку в csv, хотя, когда я запускаю эту часть в Python с помощью bs4, данные правильно отформатированы. Что мне не хватает?

Спасибо!

+0

Как устанавливаются 'jobs' и' all_jobs'? Вероятно, вам нужно сбросить переменную 'jobs' на каждую итерацию, чтобы предотвратить повторение существующих строк. – augurar

+0

@augurar Я отредактировал сообщение, чтобы отразить, как они определены. Благодарю. –

ответ

0

Я подозревал, что мне нужно «переопределить» суп для каждой новой страницы

В самом деле, вы должны. Видите ли, ваш цикл while работает с soup, всегда ссылаясь на тот же старый объект, который вы делали перед вводом этого цикла while. Вы должны перепривязывают soup к новому BeautifulSoup инстанции, который, скорее всего, вы найдете URL за anchor (тег a), который вы расположены в этих последних строках:

element=wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id='reviews']/a/span[starts-with(.,'Next')]"))) 

Вы можете получить к нему доступ только ваш soup (обратите внимание, что я не проверял это на правильность: без фактического источника страницы, я предполагаю, что):

next_link = soup.find(id='reviews').a.get('href') 

И затем, в конце вашего while цикла, вы перепривязываете бы soup:

soup = BeautifulSoup(urllib.request.urlopen(next_link.read())) 

Вы должны еще добавить пункт try - except захватить ошибку он будет генерировать на последней странице, если он не может найти последний «Next» ссылку, а затем выйти из цикла.

Отметьте, что selenium, скорее всего, не понадобится для вашего прецедента, bs4 будет достаточно (но и будет работать).

Кроме того, хотя это небольшая проблема, данные записываются по одной букве на ячейку в csv, хотя, когда я запускаю эту часть в Python с помощью bs4, данные правильно отформатированы. Что мне не хватает?

Созданный вами экземпляр writer ожидает итерации для его метода writerows. Вы передаете ему одну строку (в которой могут быть kommas, но это не то, на что будет выглядеть csv.writer: она добавит kommas (или какой бы ограничитель вы указали в его построении) между каждыми двумя элементами итерабельного). Строка Python является итерируемой (для каждого символа), поэтому writer.writerows("some_string") не приводит к ошибке. Но вы, скорее всего, хотели это:

for text in (all_jobs): 
    t = [x.strip() for x in text.find_all(text=True)] 
    jobs.append(t) 

В последующем на комментарии: Вы хотите обновить soup на основе нового URL, который вы извлекаете из 1, 2, 3 Next >> (это в div контейнере с конкретным id, поэтому его легко извлечь только BeautifulSoup). Код ниже - довольно простой пример, который показывает, как это делается. Извлечение вещей, которые вы считаете релевантными, осуществляется с помощью собственного кода очистки, который вам нужно добавить, как указано в примере.

#Python3.x 
import urllib 
from bs4 import BeautifulSoup 

url = 'http://www.indeed.com/cmp/Wesley-Medical-Center/reviews' 
base_url_parts = urllib.parse.urlparse(url) 
while True: 
    raw_html = urllib.request.urlopen(url).read() 
    soup = BeautifulSoup(raw_html) 
    # scrape the page for the desired info 
    # ... 

    last_link = soup.find('div', id='company_reviews_pagination').find_all('a')[-1] 
    if last_link.text.startswith('Next'): 
     next_url_parts = urllib.parse.urlparse(last_link['href']) 
     url = urllib.parse.urlunparse((base_url_parts.scheme, base_url_parts.netloc, 
      next_url_parts.path, next_url_parts.params, next_url_parts.query, 
      next_url_parts.fragment)) 
     print(url) 
    else: 
     break 
+0

Спасибо, я попробую это и дам вам знать, если это сработает (и скоро примите ваш ответ). Извините за задержку - путешествовали. –

+0

Хорошо, я могу быть тупым, но даже если я попробую повторно инициировать переменную супа после нажатия на каждую новую страницу, код не работает. Вот страница (-ы), которую я хочу очистить: http://www.indeed.com/cmp/Wesley-Medical-Center/reviews (это начальная страница, программа нажимает «дальше», пока не достигнет последней страница). Может ли кто-нибудь помочь? ТИА! –

+0

@anne_t, теперь, когда я вижу URL-адрес, вы хотите очистить ссылки, скрытые за «1, 2, 3, далее», или вы хотите «просмотреть эту компанию». Мое предположение - первое, и в этом случае вас будет интересовать 'soup.find ('div', id = 'company_reviews_pagination'). Find_all ('a') [- 1] ['href']', а не ' element = wait.until (... написанное выше). Остерегайтесь: возвратите относительную гиперреакцию: вам все равно нужно добавить схему и netlocation (будучи 'http: // www.indeed.com'). –