2015-07-02 4 views
4

Я изучаю Python и пытаюсь очистить этот page за конкретное значение в выпадающем меню. После этого мне нужно щелкнуть каждый элемент в приведенной таблице, чтобы получить конкретную информацию. Я могу выбрать элемент и получить информацию на веб-сервере. Но я не знаю, как передать URL-адрес ответа на crawlspider.Прохождение ответа selenium url на scrapy

driver = webdriver.Firefox() 
driver.get('http://www.cppcc.gov.cn/CMS/icms/project1/cppcc/wylibary/wjWeiYuanList.jsp') 
more_btn = WebDriverWait(driver, 20).until(
    EC.visibility_of_element_located((By.ID, '_button_select')) 
      ) 
more_btn.click() 

## select specific value from the dropdown 
driver.find_element_by_css_selector("select#tabJcwyxt_jiebie >  option[value='teyaoxgrs']").click() 
driver.find_element_by_css_selector("select#tabJcwyxt_jieci > option[value='d11jie']").click() 
search2 = driver.find_element_by_class_name('input_a2') 
search2.click() 
time.sleep(5) 

## convert html to "nice format" 
text_html=driver.page_source.encode('utf-8') 
html_str=str(text_html) 

## this is a hack that initiates a "TextResponse" object (taken from the Scrapy module) 
resp_for_scrapy=TextResponse('none',200,{},html_str,[],None) 

## convert html to "nice format" 
text_html=driver.page_source.encode('utf-8') 
html_str=str(text_html) 

resp_for_scrapy=TextResponse('none',200,{},html_str,[],None) 

Так вот, где я застрял. Я смог запросить использование вышеуказанного кода. Но как я могу пройти resp_for_scrapy до crawlspider? Я положил resp_for_scrapy вместо item но это не сработало.

## spider 
class ProfileSpider(CrawlSpider): 
name = 'pccprofile2' 
allowed_domains = ['cppcc.gov.cn'] 
start_urls = ['http://www.cppcc.gov.cn/CMS/icms/project1/cppcc/wylibary/wjWeiYuanList.jsp']  

def parse(self, resp_for_scrapy): 

    hxs = HtmlXPathSelector(resp_for_scrapy) 
    for post in resp_for_scrapy.xpath('//div[@class="table"]//ul//li'): 
     items = [] 
     item = Ppcprofile2Item() 
     item ["name"] = hxs.select("//h1/text()").extract() 
     item ["title"] = hxs.select("//div[@id='contentbody']//tr//td//text()").extract() 
     items.append(item) 

    ##click next page  
    while True: 
     next = self.driver.findElement(By.linkText("下一页")) 
     try: 
      next.click() 
     except: 
      break 

    return(items) 

Любые предложения были бы весьма благодарны !!!!

EDITS Я включил класс промежуточного программного обеспечения для выбора из раскрывающегося списка перед классом паука. Но теперь нет ошибки и никакого результата.

class JSMiddleware(object): 
    def process_request(self, request, spider): 
     driver = webdriver.PhantomJS() 
     driver.get('http://www.cppcc.gov.cn/CMS/icms/project1/cppcc/wylibary/wjWeiYuanList.jsp') 


    # select from the dropdown 
     more_btn = WebDriverWait(driver, 20).until(
     EC.visibility_of_element_located((By.ID, '_button_select')) 
       ) 
     more_btn.click() 


     driver.find_element_by_css_selector("select#tabJcwyxt_jiebie > option[value='teyaoxgrs']").click() 
     driver.find_element_by_css_selector("select#tabJcwyxt_jieci > option[value='d11jie']").click() 
     search2 = driver.find_element_by_class_name('input_a2') 
     search2.click() 
     time.sleep(5) 

     #get the response 
     body = driver.page_source 
     return HtmlResponse(driver.current_url, body=body, encoding='utf-8', request=request) 



class ProfileSpider(CrawlSpider): 
    name = 'pccprofile2' 
    rules = [Rule(SgmlLinkExtractor(allow=(),restrict_xpaths=("//div[@class='table']")), callback='parse_item')] 

    def parse_item(self, response): 
    hxs = HtmlXPathSelector(response) 
    items = [] 
    item = Ppcprofile2Item() 
    item ["name"] = hxs.select("//h1/text()").extract() 
    item ["title"] = hxs.select("//div[@id='contentbody']//tr//td//text()").extract() 
    items.append(item) 

    #click next page  
    while True: 
     next = response.findElement(By.linkText("下一页")) 
     try: 
      next.click() 
     except: 
      break 

    return(items) 

ответ

16

Использование Downloader Middleware поймать селена требуется страниц перед тем вы обрабатываете их регулярно с Scrapy:

The downloader middleware is a framework of hooks into Scrapy’s request/response processing. It’s a light, low-level system for globally altering Scrapy’s requests and responses.

Вот очень простой пример использования PhantomJS:

from scrapy.http import HtmlResponse 
from selenium import webdriver 

class JSMiddleware(object): 
    def process_request(self, request, spider): 
     driver = webdriver.PhantomJS() 
     driver.get(request.url) 

     body = driver.page_source 
     return HtmlResponse(driver.current_url, body=body, encoding='utf-8', request=request) 

После возвращения что HtmlResponse (или TextResponse, если это то, что вы действительно хотите), Scrapy прекратит обработку загрузчики и падение в parse метод паука:

If it returns a Response object, Scrapy won’t bother calling any other process_request() or process_exception() methods, or the appropriate download function; it’ll return that response. The process_response() methods of installed middleware is always called on every response.

В этом случае, вы можете продолжать использовать parse метод вашего паука, как обычно с HTML, за исключением того, что JS на странице уже выполнен.

Подсказка: Так как метод Загрузчик Middleware пакет process_request принимает паука в качестве аргумента, вы можете добавить условное в паука, чтобы проверить, нужно ли обрабатывать JS на всех, и это позволит вам обрабатывать как JS и не- JS-страницы с таким же классом пауков.

+0

Hi Joe, спасибо за предложение. Я сделал то, что вы предложили, включив класс JSMiddleware перед классом CrawlSpider. И в классе промежуточного программного обеспечения я вставил код, который я выбираю из раскрывающегося списка и нажмите. Не было результата, и ошибка не возвращалась. См. Приведенные выше изменения. –

+0

Ваше изменение не включает оператор 'return'. Убедитесь, что вы возвращаете ответ от промежуточного программного обеспечения. – JoeLinux

+0

У меня было заявление 'return'. я понял, что сейчас я получил ошибку 'от scrapy.http import HttpResponse ImportError: не могу импортировать имя HttpResponse' я посмотрю, если это проблема ... –

5

Вот промежуточный слой для Scrapy и Селен

from scrapy.http import HtmlResponse 
from scrapy.utils.python import to_bytes 
from selenium import webdriver 
from scrapy import signals 


class SeleniumMiddleware(object): 

    @classmethod 
    def from_crawler(cls, crawler): 
     middleware = cls() 
     crawler.signals.connect(middleware.spider_opened, signals.spider_opened) 
     crawler.signals.connect(middleware.spider_closed, signals.spider_closed) 
     return middleware 

    def process_request(self, request, spider): 
     request.meta['driver'] = self.driver # to access driver from response 
     self.driver.get(request.url) 
     body = to_bytes(self.driver.page_source) # body must be of type bytes 
     return HtmlResponse(self.driver.current_url, body=body, encoding='utf-8', request=request) 

    def spider_opened(self, spider): 
     self.driver = webdriver.Firefox() 

    def spider_closed(self, spider): 
     self.driver.close() 

необходим также добавить в settings.py

DOWNLOADER_MIDDLEWARES = { 
    'youproject.middlewares.selenium.SeleniumMiddleware': 200 
} 

Решает погоду его 200 или что-то другое на основе docs.

Updateсветлячок обезглавленное режим с Scrapy и селена

Если вы хотите запустить Firefox в обезглавленный режиме установите xvfb

sudo apt-get install -y xvfb 

и PyVirtualDisplay

sudo pip install pyvirtualdisplay 

и использование это промежуточное ПО

from shutil import which 

from pyvirtualdisplay import Display 
from scrapy import signals 
from scrapy.http import HtmlResponse 
from scrapy.utils.project import get_project_settings 
from selenium import webdriver 
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary 

settings = get_project_settings() 

HEADLESS = True 


class SeleniumMiddleware(object): 

    @classmethod 
    def from_crawler(cls, crawler): 
     middleware = cls() 
     crawler.signals.connect(middleware.spider_opened, signals.spider_opened) 
     crawler.signals.connect(middleware.spider_closed, signals.spider_closed) 
     return middleware 

    def process_request(self, request, spider): 
     self.driver.get(request.url) 
     request.meta['driver'] = self.driver 
     body = str.encode(self.driver.page_source) 
     return HtmlResponse(self.driver.current_url, body=body, encoding='utf-8', request=request) 

    def spider_opened(self, spider): 
     if HEADLESS: 
      self.display = Display(visible=0, size=(1280, 1024)) 
      self.display.start() 
     binary = FirefoxBinary(settings.get('FIREFOX_EXE') or which('firefox')) 
     self.driver = webdriver.Firefox(firefox_binary=binary) 

    def spider_closed(self, spider): 
     self.driver.close() 
     if HEADLESS: 
      self.display.stop() 

где settings.py содержит

FIREFOX_EXE = '/path/to/firefox.exe' 

Проблема заключается в том, что некоторые версии Firefox не работает с селеном. Для решения этой проблемы вы можете скачать firefox версию 47.0.1 (эта версия работает безупречно) от here, затем извлеките ее и поместите в проект селена. После этого измените путь firefox как

FIREFOX_EXE = '/path/to/your/scrapyproject/firefox/firefox.exe' 
Смежные вопросы