Поиск по блогу

вторник, 10 февраля 2015 г.

Слишком "подробно" заданы пути в XPath запросах carmailPrice? Нет! Надо было обработать ошибки

Когда спайдер выдает ошибки при парсинге 2/3 страниц, то начинаются упреки и подозрения. Мне удалось "поймать" паука-халтурщика на странице Daewoo, здесь я сравниваю его поведение на страницах BMW и Daewoo. Трачу на это целый день. Оказалось, что я просто ошибся с "диагнозом". Не на всех страницах модификаций есть ссылки на цены. Спайдер выдавал ошибки, но продолжал работу. Оказалось, что при этом он может пропучкать сразу десятки страниц. Но целый день я искал отличия в коде страниц, здесь фрагменты кода и запросы XPath

In []:
item['disel'] = link.xpath('.//\
 exceptions.UnboundLocalError: local variable 'link' referenced before assignment

# Вот такие ошибки были и на странице BMW, я проверил штуки три и выяснилось, что на них просто нет тега
<a href="35762/index.html" class="catalog-age__mod__item__equip clear">

# а это основной тег, вокнуг которого и проложены оси парсинга...

Хорошо, что прежде, чем писать обработку ошибок, я решил прогнать паука по всем модлеям, потом только по странице Daewoo. Здесь спайдер из 11 тегов спарсил только три... Файрбагом и Икпаз хелпером найти причину не смог. Пришлось писать этот пост.

Ниже фрагманты кода из двух страниц сайта.

In []:
Это страница седана Daewoo (file:///C:/Users/kiss/Desktop/carsmail/carsmail/cars.mail.ru/catalog/daewoo/nexia/ii/sedan/index.html)
In [1]:
<div class="catalog-age__mod__item__box">

 <div class="catalog-age__mod__item__type clear">
  <div class="catalog-age__mod__item__type__text catalog-age__mod__item__type__text_title">
   <a href="specifications/indexbd21.html?gear_type=205&amp;fuel=222&amp;modification_id=15645" class="catalog-age__mod__item__type__link">1.5 MT</a>
  </div>
  <div class="catalog-age__mod__item__type__text catalog-age__mod__item__type__text_hp">80 л.с.</div>
 </div>

 <div class="catalog-age__mod__item__note">
 Механика,
 передний&nbsp;привод,
 бензин, 12.5&nbsp;с&nbsp;до&nbsp;100&nbsp;км/ч
 </div>

 <a href="35760/index.html" class="catalog-age__mod__item__equip clear">
  <span>HC19 Classic</span>

  <div class="catalog-age__mod__item__equip__price">
   <span class="catalog-age__mod__item__equip__price__value">
    <span class="rank"><i>289</i><i>000</i></span>
   </span>
  <span class="catalog-age__mod__item__equip__price__note">руб.</span>
  </div>
 </a>
 
 <a href="35762/index.html" class="catalog-age__mod__item__equip clear">
  <span>HC19/81</span>

  <div class="catalog-age__mod__item__equip__price">
   <span class="catalog-age__mod__item__equip__price__value">
    <span class="rank"><i>329</i><i>000</i></span>
   </span>
   <span class="catalog-age__mod__item__equip__price__note">руб.</span>
  </div>
 </a>
 
 <a href="35763/index.html" class="catalog-age__mod__item__equip clear">
 <span>HC28/81</span>

 <div class="catalog-age__mod__item__equip__price">
 <span class="catalog-age__mod__item__equip__price__value">
 <span class="rank"><i>342</i><i>000</i></span>
 </span>
 <span class="catalog-age__mod__item__equip__price__note">руб.</span>
 </div>
 </a>
 
 <a href="35764/index.html" class="catalog-age__mod__item__equip clear">
 <span>HC22/81</span>

 <div class="catalog-age__mod__item__equip__price">
 <span class="catalog-age__mod__item__equip__price__value">
 <span class="rank"><i>356</i><i>000</i></span>
 </span>
 <span class="catalog-age__mod__item__equip__price__note">руб.</span>
 </div>
 </a>
 
 <a href="35766/index.html" class="catalog-age__mod__item__equip clear">
 <span>HC18</span>

 <div class="catalog-age__mod__item__equip__price">
 <span class="catalog-age__mod__item__equip__price__value">
 <span class="rank"><i>360</i><i>000</i></span>
 </span>
 <span class="catalog-age__mod__item__equip__price__note">руб.</span>
 </div>
 </a>
 
 <a href="35765/index.html" class="catalog-age__mod__item__equip clear">
 <span>HC23/18</span>

 <div class="catalog-age__mod__item__equip__price">
 <span class="catalog-age__mod__item__equip__price__value">
 <span class="rank"><i>368</i><i>000</i></span>
 </span>
 <span class="catalog-age__mod__item__equip__price__note">руб.</span>
 </div>
 </a>
 
 <a href="35767/index.html" class="catalog-age__mod__item__equip clear">
 <span>HC16</span>

 <div class="catalog-age__mod__item__equip__price">
 <span class="catalog-age__mod__item__equip__price__value">
 <span class="rank"><i>386</i><i>000</i></span>
 </span>
 <span class="catalog-age__mod__item__equip__price__note">руб.</span>
 </div>
 </a>
 
 
 </div>
  File "<ipython-input-1-57a0a1fdf911>", line 1
    <div class="catalog-age__mod__item__box">
    ^
SyntaxError: invalid syntax

А это шаблон для BMW, который я использовал для настройки ранее http://pythonr.blogspot.ru/2015/01/xpath_21.html#Вот-HTML-код-этого-фрагмента-для-парсинга

In [2]:
<div class="catalog-age__mod__item__box">

 <div class="catalog-age__mod__item__type clear">
  <div class="catalog-age__mod__item__type__text catalog-age__mod__item__type__text_title">
   <a href="https://cars.mail.ru/catalog/bmw/3/f30_31/sedan/specifications/?gear_type=204&amp;fuel=59&amp;modification_id=22939" class="catalog-age__mod__item__type__link">320d 184hp xDrive AT</a>
  </div>
  <div class="catalog-age__mod__item__type__text catalog-age__mod__item__type__text_hp">184 л.с.</div>
 </div>

 <div class="catalog-age__mod__item__note">
  Автомат,
  полный&nbsp;привод,
  дизель, 7.4&nbsp;с&nbsp;до&nbsp;100&nbsp;км/ч
 </div>

  <a href="https://cars.mail.ru/catalog/bmw/3/f30_31/sedan/30440/" class="catalog-age__mod__item__equip clear">
  <span>Sport Line SKD</span>
  <div class="catalog-age__mod__item__equip__price">
   <span class="catalog-age__mod__item__equip__price__value">
    <span class="rank"><i>1</i><i>752</i><i>000</i></span>
   </span>
   <span class="catalog-age__mod__item__equip__price__note">руб.</span>
  </div>
  </a>
 
 <a href="https://cars.mail.ru/catalog/bmw/3/f30_31/sedan/35796/" class="catalog-age__mod__item__equip clear">
  <span>Modern Line SKD</span>

  <div class="catalog-age__mod__item__equip__price">
   <span class="catalog-age__mod__item__equip__price__value">
    <span class="rank"><i>1</i><i>883</i><i>000</i></span>
   </span>
   <span class="catalog-age__mod__item__equip__price__note">руб.</span>
  </div>
 </a>
 
 <a href="https://cars.mail.ru/catalog/bmw/3/f30_31/sedan/30439/" class="catalog-age__mod__item__equip clear">
   <span>Luxury Line SKD</span>

  <div class="catalog-age__mod__item__equip__price">
   <span class="catalog-age__mod__item__equip__price__value">
    <span class="rank"><i>1</i><i>950</i><i>000</i></span>
   </span>
   <span class="catalog-age__mod__item__equip__price__note">руб.</span>
  </div>
 </a>
 
 </div>
  File "<ipython-input-2-8187b3b71aaf>", line 1
    <div class="catalog-age__mod__item__box">
    ^
SyntaxError: invalid syntax
In [4]:
from lxml import html
daewoo = html.fromstring(In[1])
bmw = html.fromstring(In[2])

Начнем с того, что работало в обоих случаях

In []:
#Сначала мы находим в цикле наш главнй тег класса  
#это тег **a**, а не **div** !
<a href="..          ." class="catalog-age__mod__item__equip clear">

# Потом находим его старшего(предшественника) брата
# братьев div всего два, поэтому нам здесь и класс нужен
preceding-sibling::div[@class="catalog-age__mod__item__type clear"]
In []:
item['modification'] = link.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"] \
/div[@class="catalog-age__mod__item__type__text catalog-age__mod_\
_item__type__text_title"]/a/text()').extract()
In [13]:
bmw.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"] \
/div[@class="catalog-age__mod__item__type__text catalog-age__mod_\
_item__type__text_title"]/a/text()')
Out[13]:
['320d 184hp xDrive AT']
In [14]:
daewoo.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"] \
/div[@class="catalog-age__mod__item__type__text catalog-age__mod_\
_item__type__text_title"]/a/text()')
Out[14]:
['1.5 MT']
In [16]:
bmw.xpath('//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"] \
/div[@class="catalog-age__mod__item__type__text catalog-age__mod_\
_item__type__text_title"]/a/text()')
Out[16]:
['320d 184hp xDrive AT']

Видим, что все работает, как и ожидалось. Отметим, что код здесь мы немного упростили. Уьрали .extract() Однако, не понимаю, почемы находится только первый элемент из списка. Попробуем цикл, как в carmailPrice spider

Соберем все элементы в цикле

In [23]:
bmw_link_list = bmw.xpath('.//a[@class="catalog-age__mod__item__equip clear"]')
In [24]:
for link in bmw_link_list:
   print link.xpath('//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"] \
/div[@class="catalog-age__mod__item__type__text catalog-age__mod_\
_item__type__text_title"]/a/text()')
['320d 184hp xDrive AT']
['320d 184hp xDrive AT']
['320d 184hp xDrive AT']

In [20]:
daewoo_link_list = daewoo.xpath('.//a[@class="catalog-age__mod__item__equip clear"]')
In [25]:
for link in daewoo_link_list:
   print link.xpath('//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"] \
/div[@class="catalog-age__mod__item__type__text catalog-age__mod_\
_item__type__text_title"]/a/text()')
['1.5 MT']
['1.5 MT']
['1.5 MT']
['1.5 MT']
['1.5 MT']
['1.5 MT']
['1.5 MT']

In [28]:
daewoo_link_list
Out[28]:
[<Element a at 0x4138638>,
 <Element a at 0x4138688>,
 <Element a at 0x4138728>,
 <Element a at 0x4138778>,
 <Element a at 0x41387c8>,
 <Element a at 0x4138818>,
 <Element a at 0x4138868>]

Теперь пробуем то, что выдавало ошибку

In []:
item['link_to_spec'] = link.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"]/\
div[@class="catalog-age__mod__item__type__text catalog-age__mod__item__type__text_title"]\
/a/@href').extract()
In [32]:
bmw.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"]/\
div[@class="catalog-age__mod__item__type__text catalog-age__mod__item__type__text_title"]\
/a/@href')
Out[32]:
['https://cars.mail.ru/catalog/bmw/3/f30_31/sedan/specifications/?gear_type=204&fuel=59&modification_id=22939']
In [33]:
daewoo.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"]/\
div[@class="catalog-age__mod__item__type__text catalog-age__mod__item__type__text_title"]\
/a/@href')
Out[33]:
['specifications/indexbd21.html?gear_type=205&fuel=222&modification_id=15645']
In []:
# Этот путь ведет от каждого главного тега  к первому тегу div
# мы его отличаем по классу
div[@class="catalog-age__mod__item__type clear"]

# а в него влолжен div с двумя длиннющими классами
div[@class="catalog-age__mod__item__type__text catalog-age__mod__item__type__text_title"]
# их бы заменить ?
#
In [34]:
for link in daewoo_link_list:
   print link.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"]/\
div[@class="catalog-age__mod__item__type__text catalog-age__mod__item__type__text_title"]\
/a/@href')
['specifications/indexbd21.html?gear_type=205&fuel=222&modification_id=15645']
['specifications/indexbd21.html?gear_type=205&fuel=222&modification_id=15645']
['specifications/indexbd21.html?gear_type=205&fuel=222&modification_id=15645']
['specifications/indexbd21.html?gear_type=205&fuel=222&modification_id=15645']
['specifications/indexbd21.html?gear_type=205&fuel=222&modification_id=15645']
['specifications/indexbd21.html?gear_type=205&fuel=222&modification_id=15645']
['specifications/indexbd21.html?gear_type=205&fuel=222&modification_id=15645']

Не понимаю, почему здесь все работает, пока пойдем дальше. Когда я закоментировал эту строчку, то ошибку стал выдавать вот этот код:

In []:
#       Автомат, полный привод, дизель, 7.4 с до 100 км/ч
item['disel'] = link.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__note"]/text()').extract()
In [38]:
for link in daewoo_link_list:
   print link.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__note"]/text()') # и здесь я тоже убрал .extract()
[u'\n \u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430,\n \u043f\u0435\u0440\u0435\u0434\u043d\u0438\u0439\xa0\u043f\u0440\u0438\u0432\u043e\u0434,\n \u0431\u0435\u043d\u0437\u0438\u043d, 12.5\xa0\u0441\xa0\u0434\u043e\xa0100\xa0\u043a\u043c/\u0447\n ']
[u'\n \u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430,\n \u043f\u0435\u0440\u0435\u0434\u043d\u0438\u0439\xa0\u043f\u0440\u0438\u0432\u043e\u0434,\n \u0431\u0435\u043d\u0437\u0438\u043d, 12.5\xa0\u0441\xa0\u0434\u043e\xa0100\xa0\u043a\u043c/\u0447\n ']
[u'\n \u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430,\n \u043f\u0435\u0440\u0435\u0434\u043d\u0438\u0439\xa0\u043f\u0440\u0438\u0432\u043e\u0434,\n \u0431\u0435\u043d\u0437\u0438\u043d, 12.5\xa0\u0441\xa0\u0434\u043e\xa0100\xa0\u043a\u043c/\u0447\n ']
[u'\n \u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430,\n \u043f\u0435\u0440\u0435\u0434\u043d\u0438\u0439\xa0\u043f\u0440\u0438\u0432\u043e\u0434,\n \u0431\u0435\u043d\u0437\u0438\u043d, 12.5\xa0\u0441\xa0\u0434\u043e\xa0100\xa0\u043a\u043c/\u0447\n ']
[u'\n \u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430,\n \u043f\u0435\u0440\u0435\u0434\u043d\u0438\u0439\xa0\u043f\u0440\u0438\u0432\u043e\u0434,\n \u0431\u0435\u043d\u0437\u0438\u043d, 12.5\xa0\u0441\xa0\u0434\u043e\xa0100\xa0\u043a\u043c/\u0447\n ']
[u'\n \u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430,\n \u043f\u0435\u0440\u0435\u0434\u043d\u0438\u0439\xa0\u043f\u0440\u0438\u0432\u043e\u0434,\n \u0431\u0435\u043d\u0437\u0438\u043d, 12.5\xa0\u0441\xa0\u0434\u043e\xa0100\xa0\u043a\u043c/\u0447\n ']
[u'\n \u041c\u0435\u0445\u0430\u043d\u0438\u043a\u0430,\n \u043f\u0435\u0440\u0435\u0434\u043d\u0438\u0439\xa0\u043f\u0440\u0438\u0432\u043e\u0434,\n \u0431\u0435\u043d\u0437\u0438\u043d, 12.5\xa0\u0441\xa0\u0434\u043e\xa0100\xa0\u043a\u043c/\u0447\n ']

In [43]:
d = daewoo.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__note"]/text()') # и здесь я тоже убрал .extract()
print ' '.join(d)
 Механика,
 передний привод,
 бензин, 12.5 с до 100 км/ч
 

In [44]:
bmw_link_list_a = bmw.xpath('//a[@class="catalog-age__mod__item__equip clear"]')
In [45]:
bmw_link_list_a
Out[45]:
[<Element a at 0x4138368>, <Element a at 0x4138408>, <Element a at 0x4138458>]
In []:
#bmw 
# Все модели на странице 
# file:///C:/Users/kiss/Desktop/carsmail/carsmail/cars.mail.ru/catalog/bmw/index.html
----------------------------
catalog-generation
  catalog-generation__title
  catalog-generation__list
  ...
  ...
  catalog-generation__title
  catalog-generation__list    
---------------------------    
catalog-age__mod__list js-catalog_mod_list
In []:
catalog-age__mod__list js-catalog_mod_list
In [47]:
bmw.xpath('.//\
preceding-sibling::div[@class="catalog-age__mod__item__type clear"]/\
div[@class="catalog-age__mod__item__type__text catalog-age__mod__item_\
_type__text_hp"]/text()')
Out[47]:
[u'184 \u043b.\u0441.']


Посты чуть ниже также могут вас заинтересовать

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

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