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

пятница, 8 августа 2014 г.

Понял, как подменять user-agent Scrapy shell...

Как менять параметры запроса в Scrapy shell? При запуске shell можно менять константы (объекта) settings, а при работе из запущенной оболочки shell можно менять параметры (словаря) объекта запроса response в команде fetch(myresponse). В первом случае надо найти в документации, как пишется -s USER_AGENT, а во втором распечатать словарь объекта request.headers { ... 'User-Agent': 'Scrapy/0.20.1 (+http://scrapy.org)'}
Начнем практику с работающего примера. Для этого возьмем первую строчку start_urls из проверенного примера Dirbot "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/"
Мы уже проверили ранее и знаем, что этот url загружается при настройках по умолчанию. Но вот они - первые трудности. Оказалось, что при запуске оболочки из папки проекта, настройки паука подхватываются по умолчанию. А в документации вроде бы по другому написано ?

Запуск scrapy shell из папки проекта выдает ошибку потому-что автоматически находится и подключается (недоделаный мной) паук проекта 'BOT_NAME': 'test_url'

In []:
C:\Users\kiss\Documents\GitMyScrapy\scrapy_mahmoud_1\mahmoud_1>scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Pyt
hon/Books/"  -s 'USER-AGENT'='Mozilla-5.0'
2014-08-11 15:40:18+0400 [scrapy] INFO: Scrapy 0.20.1 started (bot: test_url)
2014-08-11 15:40:18+0400 [scrapy] DEBUG: Optional features available: ssl, http11, boto, django
2014-08-11 15:40:18+0400 [scrapy] DEBUG: Overridden settings: {'NEWSPIDER_MODULE': 'mahmoud_1.spiders', 'SPIDER_MODULES': ['mahmoud_
1.spiders'], 'LOGSTATS_INTERVAL': 0, 'BOT_NAME': 'test_url'}
2014-08-11 15:40:19+0400 [scrapy] DEBUG: Enabled extensions: TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState
2014-08-11 15:40:20+0400 [scrapy] DEBUG: Enabled downloader middlewares: ProxyMiddleware, HttpAuthMiddleware, DownloadTimeoutMiddlew
are, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, MetaRefreshMiddleware, HttpCompressionMiddleware, RedirectMiddl
eware, CookiesMiddleware, ChunkedTransferMiddleware, DownloaderStats
2014-08-11 15:40:20+0400 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlL
engthMiddleware, DepthMiddleware
2014-08-11 15:40:20+0400 [scrapy] DEBUG: Enabled item pipelines:
2014-08-11 15:40:20+0400 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023
2014-08-11 15:40:20+0400 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080
2014-08-11 15:40:20+0400 [default] INFO: Spider opened
Traceback (most recent call last):
  File "C:\Users\kiss\Anaconda\lib\runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "C:\Users\kiss\Anaconda\lib\runpy.py", line 72, in _run_code
    exec code in run_globals
  File "C:\Users\kiss\Anaconda\lib\site-packages\scrapy\cmdline.py", line 168, in <module>
    execute()
  File "C:\Users\kiss\Anaconda\lib\site-packages\scrapy\cmdline.py", line 143, in execute
    _run_print_help(parser, _run_command, cmd, args, opts)
  File "C:\Users\kiss\Anaconda\lib\site-packages\scrapy\cmdline.py", line 89, in _run_print_help
    func(*a, **kw)
  File "C:\Users\kiss\Anaconda\lib\site-packages\scrapy\cmdline.py", line 150, in _run_command
    cmd.run(args, opts)
  File "C:\Users\kiss\Anaconda\lib\site-packages\scrapy\commands\shell.py", line 50, in run
    shell.start(url=url, spider=spider)
  File "C:\Users\kiss\Anaconda\lib\site-packages\scrapy\shell.py", line 43, in start
    self.fetch(url, spider)
  File "C:\Users\kiss\Anaconda\lib\site-packages\scrapy\shell.py", line 88, in fetch
    reactor, self._schedule, request, spider)
  File "C:\Users\kiss\Anaconda\lib\site-packages\twisted\internet\threads.py", line 122, in blockingCallFromThread
    result.raiseException()
  File "<string>", line 2, in raiseException
TypeError: argument of type 'NoneType' is not iterable

Выходим из папки проекта (с файлом .cfg) и та же команда не находит пауков и запусает SHELL с другой строкой Overridden settings:

In []:
C:\Users\kiss\Documents\GitMyScrapy\scrapy_mahmoud_1\mahmoud_1>cd ..\

C:\Users\kiss\Documents\GitMyScrapy\scrapy_mahmoud_1>scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/
"  -s 'USER-AGENT'='Mozilla-5.0'
2014-08-11 15:41:39+0400 [scrapy] INFO: Scrapy 0.20.1 started (bot: scrapybot)
2014-08-11 15:41:39+0400 [scrapy] DEBUG: Optional features available: ssl, http11, boto, django
2014-08-11 15:41:39+0400 [scrapy] DEBUG: Overridden settings: {'LOGSTATS_INTERVAL': 0}
2014-08-11 15:41:41+0400 [scrapy] DEBUG: Enabled extensions: TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState
2014-08-11 15:41:42+0400 [scrapy] DEBUG: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMid
dleware, RetryMiddleware, DefaultHeadersMiddleware, MetaRefreshMiddleware, HttpCompressionMiddleware, RedirectMiddleware, CookiesMid
dleware, ChunkedTransferMiddleware, DownloaderStats
2014-08-11 15:41:42+0400 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlL
engthMiddleware, DepthMiddleware
2014-08-11 15:41:42+0400 [scrapy] DEBUG: Enabled item pipelines:
2014-08-11 15:41:42+0400 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023
2014-08-11 15:41:42+0400 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080
2014-08-11 15:41:42+0400 [default] INFO: Spider opened
2014-08-11 15:41:42+0400 [default] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (ref
erer: None)
[s] Available Scrapy objects:
[s]   item       {}
[s]   request    <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
[s]   response   <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
[s]   sel        <Selector xpath=None data=u'<html lang="en">\r\n<head>\r\n<meta http-equ'>
[s]   settings   <CrawlerSettings module=None>
[s]   spider     <BaseSpider 'default' at 0x480b940>
[s] Useful shortcuts:
[s]   shelp()           Shell help (print this help)
[s]   fetch(req_or_url) Fetch request (or URL) and update local objects
[s]   view(response)    View response in a browser
C:\Users\kiss\Anaconda\lib\site-packages\IPython\frontend.py:30: UserWarning: The top-level `frontend` package has been deprecated.
All its subpackages have been moved to the top `IPython` level.
  warn("The top-level `frontend` package has been deprecated. "

In [1]:

Первым делом проверим, что за запрос мы отправили

In []:
In [3]: request.headers
Out[3]:
{'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
 'Accept-Encoding': 'x-gzip,gzip,deflate',
 'Accept-Language': 'en',
 'User-Agent': 'Scrapy/0.20.1 (+http://scrapy.org)'}
Интересно, в команде вызова мы попытались установить опцию -s 'USER-AGENT'='Mozilla-5.0'. Что сделали неправильно? Вариагнты: Python чувствителен к регистру, кавычки здесь нужны (?)... Но для начала посмотрим справку еще раз. Она тоже покажет разные наборы команд в зависимости от того, находимся ли мы в папке проекта:
In []:
C:\Users\kiss\Documents\GitMyScrapy\scrapy_mahmoud_1\mahmoud_1>scrapy shell -h
Usage
=====
  scrapy shell [url|file]

Interactive console for scraping the given url

Options
=======
--help, -h              show this help message and exit
-c CODE                 evaluate the code in the shell, print the result and
                        exit
--spider=SPIDER         use this spider

Global Options
--------------
--logfile=FILE          log file. if omitted stderr will be used
--loglevel=LEVEL, -L LEVEL
                        log level (default: DEBUG)
--nolog                 disable logging completely
--profile=FILE          write python cProfile stats to FILE
--lsprof=FILE           write lsprof profiling stats to FILE
--pidfile=FILE          write process ID to FILE
--set=NAME=VALUE, -s NAME=VALUE
                        set/override setting (may be repeated)
--pdb                   enable pdb on failure

Ответ от удаленного сервера мы получили нормальный ... и с куками

In []:
In [6]: response.headers
Out[6]:
{'Content-Language': 'en',
 'Content-Type': 'text/html;charset=UTF-8',
 'Cteonnt-Length': '33758',
 'Date': 'Mon, 11 Aug 2014 11:41:50 GMT',
 'Server': 'Apache',
 'Set-Cookie': 'JSESSIONID=61C7C76C40ED10E398252B049C0DAE22; Path=/'}
Мы уже знаем, что большинство серверов не желают разговаривать со 'User-Agent': 'Scrapy/0.20.1 (+http://scrapy.org)' А у нас подменить агента не получилось. Как мы это сделали ранее вот в этом посте Продолжаем осваивать Scrapy shell - пытаемся понять и запомнить то, что выскакивает после .TAB в консоли iPython
Мы там начали читать Populating the settings
Здесь мы попробуем найти все варианты. Сначала распечатаем, что имеем:
In []:
In [7]: settings['USER_AGENT']
Out[7]: 'Scrapy/0.20.1 (+http://scrapy.org)'
И тут я вспомнил, что все это объекты в рабочей области... Что мне мешает создать свой запрос из предыдущего, а потом изменить часть этого запроса, а потом использовать команду fetch(myrequest) вместо fetch(URL).
Это же совсем другое дело, когда можно использовать для вызова целый объект:
In []:
In [39]: re=request.headers

In [40]: re['User-Agent']
Out[40]: 'Scrapy/0.20.1 (+http://scrapy.org)'

In [41]: re['User-Agent']='Mozzziil-5'
Но попытка вызова закончилась ошибкой. Надо было не мелочиться, а сразу присвоить целый объект (а не re=request.headers). После ошибки я все это переприсвоил:
In []:
In [43]: re=request

In [44]: re.headers
Out[44]:
{'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
 'Accept-Encoding': 'x-gzip,gzip,deflate',
 'Accept-Language': 'en',
 'User-Agent': 'Mozzziil-5'}

In [45]: re.
re.body        re.cookies     re.dont_filter re.errback     re.meta        re.priority    re.url
re.callback    re.copy        re.encoding    re.headers     re.method      re.replace
И оказалось, что ранее присвоенный элемент словаря 'User-Agent': 'Mozzziil-5' сохранился (что непонятно... надо будет подумать). Теперь выполним новый запрос:
In []:
In [45]: fetch(re)
2014-08-11 17:21:38+0400 [default] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (ref
erer: None)
[s] Available Scrapy objects:
[s]   item       {}
[s]   re         <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
[s]   request    <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
[s]   response   <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
[s]   sel        <Selector xpath=None data=u'<html lang="en">\r\n<head>\r\n<meta http-equ'>
[s]   settings   <CrawlerSettings module=None>
[s]   spider     <BaseSpider 'default' at 0x480b940>
[s] Useful shortcuts:
[s]   shelp()           Shell help (print this help)
[s]   fetch(req_or_url) Fetch request (or URL) and update local objects
[s]   view(response)    View response in a browser

In [46]: response.headers
Out[46]:
{'Content-Language': 'en',
 'Content-Type': 'text/html;charset=UTF-8',
 'Cteonnt-Length': '33758',
 'Date': 'Mon, 11 Aug 2014 13:21:46 GMT',
 'Server': 'Apache',
 'Set-Cookie': 'JSESSIONID=9CEC4A497F2EA06FDE988E810D5C4213; Path=/'}
Получим новые куки (номера почти совпадают), и поищем, как посмотреть user-agent:
In []:
In [47]: response.headers.
response.headers.appendlist     response.headers.has_key        response.headers.normvalue      response.headers.update
response.headers.clear          response.headers.items          response.headers.pop            response.headers.values
response.headers.copy           response.headers.iteritems      response.headers.popitem        response.headers.viewitems
response.headers.encoding       response.headers.iterkeys       response.headers.setdefault     response.headers.viewkeys
response.headers.fromkeys       response.headers.itervalues     response.headers.setlist        response.headers.viewvalues
response.headers.get            response.headers.keys           response.headers.setlistdefault
response.headers.getlist        response.headers.normkey        response.headers.to_string

In [47]: response.
response.body            response.encoding        response.meta            response.status
response.body_as_unicode response.flags           response.replace         response.url
response.copy            response.headers         response.request

In [47]: response.request
Out[47]: <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>

In [48]: response.request.
response.request.body        response.request.dont_filter response.request.meta        response.request.url
response.request.callback    response.request.encoding    response.request.method
response.request.cookies     response.request.errback     response.request.priority
response.request.copy        response.request.headers     response.request.replace

In [48]: response.request.headers
Out[48]:
{'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
 'Accept-Encoding': 'x-gzip,gzip,deflate',
 'Accept-Language': 'en',
 'Cookie': 'JSESSIONID=61C7C76C40ED10E398252B049C0DAE22',
 'User-Agent': 'Mozzziil-5'}
Я здесь вспомнил, что объект response включает в себя и объект request... Если помнить все это, то таким образом можно снова и снова изменять мой обект запроса "re"...В оболочке шаг за шагом можно экспериментировать с любыми свойствами объекта запроса.

Так как же менять заголовок при первом вызове shell Убрать кавычки

In []:
#It works when I tried to override the user agent globally:

scrapy crawl myproject.com -o output.csv -t csv -s USER_AGENT="Mozilla...."
In []:
Всего-навсего присваиваем константу
In []:
C:\Users\kiss\Documents\GitMyScrapy\scrapy_mahmoud_1>scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/
"  -s USER_AGENT='Mozilla-5.0'
2014-08-11 18:45:23+0400 [scrapy] INFO: Scrapy 0.20.1 started (bot: scrapybot)
2014-08-11 18:45:23+0400 [scrapy] DEBUG: Optional features available: ssl, http11, boto, django
2014-08-11 18:45:23+0400 [scrapy] DEBUG: Overridden settings: {'LOGSTATS_INTERVAL': 0, 'USER_AGENT': "'Mozilla-5.0'"}
2014-08-11 18:45:24+0400 [scrapy] DEBUG: Enabled extensions: TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState
2014-08-11 18:45:25+0400 [scrapy] DEBUG: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMid
dleware, RetryMiddleware, DefaultHeadersMiddleware, MetaRefreshMiddleware, HttpCompressionMiddleware, RedirectMiddleware, CookiesMid
dleware, ChunkedTransferMiddleware, DownloaderStats
2014-08-11 18:45:25+0400 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlL
engthMiddleware, DepthMiddleware
2014-08-11 18:45:25+0400 [scrapy] DEBUG: Enabled item pipelines:
2014-08-11 18:45:25+0400 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023
2014-08-11 18:45:25+0400 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080
2014-08-11 18:45:25+0400 [default] INFO: Spider opened
2014-08-11 18:45:25+0400 [default] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (ref
erer: None)
[s] Available Scrapy objects:
[s]   item       {}
[s]   request    <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
[s]   response   <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
[s]   sel        <Selector xpath=None data=u'<html lang="en">\r\n<head>\r\n<meta http-equ'>
[s]   settings   <CrawlerSettings module=None>
[s]   spider     <BaseSpider 'default' at 0x491b898>
[s] Useful shortcuts:
[s]   shelp()           Shell help (print this help)
[s]   fetch(req_or_url) Fetch request (or URL) and update local objects
[s]   view(response)    View response in a browser
C:\Users\kiss\Anaconda\lib\site-packages\IPython\frontend.py:30: UserWarning: The top-level `frontend` package has been deprecated.
All its subpackages have been moved to the top `IPython` level.
  warn("The top-level `frontend` package has been deprecated. "

In [1]: request.headers
Out[1]:
{'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
 'Accept-Encoding': 'x-gzip,gzip,deflate',
 'Accept-Language': 'en',
 'User-Agent': "'Mozilla-5.0'"}
Итак, вместо того, чтобы присвоить константу, я написал бессмыслицу типа -s ''='', надо еще обратить внимание, что в константах USER_AGENT используется подчерк, а в словаре - дефис. Осталось теперь разобраться, где я могу найти, как пишется та или иная константа. Очевидно, что на этот глупый вопрос есть ответ в документации Settings
Слабое оправдание моей глупости в том, что здесь справочник констант не выделен в отдельный файл.
In []:
In [49]: sel.
sel.css                sel.namespaces         sel.remove_namespaces  sel.text
sel.extract            sel.re                 sel.response           sel.type
sel.extract_unquoted   sel.register_namespace sel.select             sel.xpath
Если присмотрется, то оказывается, что 'User-Agent': "'Mozilla-5.0'" в этой строке кавычки лишние. Они уместны только, если в строке есть пробелы, не так ли... Надо бы проверить.


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

2 комментария:

  1. Вот какой должна быть строчка изменения user-agent на лету

    scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books -s USER_AGENT="Mozilla/5.0 (Windows NT 6.3; WOW64)"

    USER_AGENT - это константа в scrapy, а USER-AGENT - это ключ в заголовке

    Меня по неопытности сбили с толку значения ключей (в тексте поста)

    ОтветитьУдалить
    Ответы
    1. И, чтобы все совсем было ясно:
      ключ
      -s
      можно использовать многократно
      а список констант Scrapy есть в справке в разделе http://doc.scrapy.org/en/latest/topics/settings.html#built-in-settings-reference

      Удалить