Парсинг с помощью __doPostBack со скрытым URL ссылки

Я пытаюсь получить результаты поиска с веб-сайта, который использует функцию __doPostBack. Веб-страница отображает 10 результатов на поисковый запрос. Чтобы увидеть больше результатов, нужно нажать кнопку, которая запускает __doPostBack javascript. После некоторых исследований я понял, что запрос POST ведет себя точно так же, как форма, и что для заполнения этой формы можно просто использовать FormRequest от scrapy. Я использовал следующую нить:

Проблемы при использовании метода scrapy с методом __doPostBack javascript

написать следующий скрипт.

# -*- coding: utf-8 -*- 
from scrapy.contrib.spiders import CrawlSpider
from scrapy.http import FormRequest
from scrapy.http import Request
from scrapy.selector import Selector
from ahram.items import AhramItem
import re

class MySpider(CrawlSpider):
    name = u"el_ahram2"

    def start_requests(self):
        search_term = u'اقتصاد'
        baseUrl = u'http://digital.ahram.org.eg/sresult.aspx?srch=' + search_term + u'&archid=1'
        requests = []
        for i in range(1, 4):#crawl first 3 pages as a test
            argument =  u"'Page$"+ str(i+1) + u"'"
            data = {'__EVENTTARGET': u"'GridView1'", '__EVENTARGUMENT': argument}
            currentPage = FormRequest(baseUrl, formdata = data, callback = self.fetch_articles)
            requests.append(currentPage)
        return requests

    def fetch_articles(self, response):
        sel = Selector(response)
        for ref in sel.xpath("//a[contains(@href,'checkpart.aspx?Serial=')]/@href").extract(): 
            yield Request('http://digital.ahram.org.eg/' + ref, callback=self.parse_items)

    def parse_items(self, response):
        sel = Selector(response)
        the_title = ' '.join(sel.xpath("//title/text()").extract()).replace('\n','').replace('\r','').replace('\t','')#* mean 'anything'
        the_authors = '---'.join(sel.xpath("//*[contains(@id,'editorsdatalst_HyperLink')]//text()").extract())
        the_text = ' '.join(sel.xpath("//span[@id='TextBox2']/text()").extract())
        the_month_year = ' '.join(sel.xpath("string(//span[@id = 'Label1'])").extract())
        the_day = ' '.join(sel.xpath("string(//span[@id = 'Label2'])").extract())
        item = AhramItem()
        item["Authors"] = the_authors
        item["Title"] = the_title
        item["MonthYear"] = the_month_year
        item["Day"] = the_day
        item['Text'] = the_text
        return item

Теперь моя проблема в том, что fetch_articles никогда не вызывается:

2014-05-27 12:19:12+0200 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080
2014-05-27 12:19:13+0200 [el_ahram2] DEBUG: Crawled (200) <POST     http://digital.ahram.org.eg/sresult.aspx?srch=%D8%A7%D9%82%D8%AA%D8%B5%D8%A7%D8%AF&archid=1> (referer: None)
2014-05-27 12:19:13+0200 [el_ahram2] DEBUG: Crawled (200) <POST http://digital.ahram.org.eg/sresult.aspx?srch=%D8%A7%D9%82%D8%AA%D8%B5%D8%A7%D8%AF&archid=1> (referer: None)
2014-05-27 12:19:13+0200 [el_ahram2] DEBUG: Crawled (200) <POST http://digital.ahram.org.eg/sresult.aspx?srch=%D8%A7%D9%82%D8%AA%D8%B5%D8%A7%D8%AF&archid=1> (referer: None)
2014-05-27 12:19:13+0200 [el_ahram2] INFO: Closing spider (finished)

После нескольких дней поисков я чувствую себя совершенно застрявшим. Я новичок в питоне, поэтому, возможно, ошибка тривиальна. Однако, если это не так, эта тема может быть полезна для многих людей. Заранее спасибо за помощь.


person user3679030    schedule 27.05.2014    source источник
comment
Можете ли вы попробовать наследование от BaseSpider, а не от CrawlSpider?   -  person Biswanath    schedule 27.05.2014
comment
Я только что сделал, и я получаю те же результаты. Возможно, я не совсем понимаю разницу между BaseSpider и CrawlSpider, но мне не ясно, что это должно что-то изменить.   -  person user3679030    schedule 28.05.2014


Ответы (2)


Ваш код в порядке. fetch_articles работает. Вы можете проверить это, добавив оператор печати.

Однако веб-сайт требует, чтобы вы подтверждали запросы POST. Чтобы проверить их, вы должны иметь __EVENTVALIDATION и __VIEWSTATE в теле запроса, чтобы доказать, что вы отвечаете на их форму. Чтобы получить их, вам нужно сначала сделать запрос GET и извлечь эти поля из формы. Если вы этого не сделаете, вместо этого вы получите страницу с ошибкой, которая не содержит никаких ссылок с "checkpart.aspx?Serial=", поэтому ваш цикл for не выполнялся.

Вот как я настроил start_request, а затем fetch_search делает то, что раньше делал start_request.

class MySpider(CrawlSpider):
    name = u"el_ahram2"

    def start_requests(self):
        search_term = u'اقتصاد'
        baseUrl = u'http://digital.ahram.org.eg/sresult.aspx?srch=' + search_term + u'&archid=1'
        SearchPage = Request(baseUrl, callback = self.fetch_search)
        return [SearchPage]

    def fetch_search(self, response):
        sel = Selector(response)
        search_term = u'اقتصاد'
        baseUrl = u'http://digital.ahram.org.eg/sresult.aspx?srch=' + search_term + u'&archid=1'
        viewstate = sel.xpath("//input[@id='__VIEWSTATE']/@value").extract().pop()
        eventvalidation = sel.xpath("//input[@id='__EVENTVALIDATION']/@value").extract().pop()
        for i in range(1, 4):#crawl first 3 pages as a test
            argument =  u"'Page$"+ str(i+1) + u"'"
            data = {'__EVENTTARGET': u"'GridView1'", '__EVENTARGUMENT': argument, '__VIEWSTATE': viewstate, '__EVENTVALIDATION': eventvalidation}
            currentPage = FormRequest(baseUrl, formdata = data, callback = self.fetch_articles)
            yield currentPage

    ...
person Jonathan Villemaire-Krajden    schedule 18.06.2014
comment
Спасибо, что решили это! Теперь код работает отлично! - person user3679030; 19.06.2014

 def fetch_articles(self, response):
    sel = Selector(response)
    print response._get_body() # you can write to file and do an grep 
    for ref in sel.xpath("//a[contains(@href,'checkpart.aspx?Serial=')]/@href").extract(): 
        yield Request('http://digital.ahram.org.eg/' + ref, callback=self.parse_items)

Я не смог найти "checkpart.aspx?Serial=", который вы ищете.

Это может не решить вашу проблему, но использовать ответ вместо комментария для форматирования кода.

person Biswanath    schedule 30.05.2014
comment
Спасибо за подсказку. Я не знал, что могу проверить содержимое ответа с помощью _get_body(). Вы правы, что в ответе нет checkpart.aspx?Serial=. Интересно, почему... Я предполагаю, что что-то не так с заполнением формы javascript. Хотя я не знаю, что именно. - person user3679030; 01.06.2014