stu*_*ent 9 python web-crawler scrapy web-scraping scrapy-spider
我是scrapy的新手我想从这个网站上提取每个广告的所有内容.所以我尝试了以下方法:
from scrapy.spiders import Spider
from craigslist_sample.items import CraigslistSampleItem
from scrapy.selector import Selector
class MySpider(Spider):
name = "craig"
allowed_domains = ["craigslist.org"]
start_urls = ["http://sfbay.craigslist.org/search/npo"]
def parse(self, response):
links = response.selector.xpath(".//*[@id='sortable-results']//ul//li//p")
for link in links:
content = link.xpath(".//*[@id='titletextonly']").extract()
title = link.xpath("a/@href").extract()
print(title,content)
Run Code Online (Sandbox Code Playgroud)
项目:
# Define here the models for your scraped items
from scrapy.item import Item, Field
class CraigslistSampleItem(Item):
title = Field()
link = Field()
Run Code Online (Sandbox Code Playgroud)
但是,当我运行爬虫时,我什么都没得到:
$ scrapy crawl --nolog craig
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
Run Code Online (Sandbox Code Playgroud)
因此,我的问题是:我如何遍历每个网址,进入每个链接并抓取内容和标题?,这是最好的方法吗?
Iva*_*aer 13
如果您想要抓取,可能需要查看CrawlSpider
.
要构建一个基本的scrapy项目,您可以使用以下命令:
scrapy startproject craig
Run Code Online (Sandbox Code Playgroud)
然后添加蜘蛛和物品:
克雷格/蜘蛛/ spider.py
from scrapy.spiders import CrawlSpider, Rule
from craig.items import CraigslistSampleItem
from scrapy.linkextractors.lxmlhtml import LxmlLinkExtractor
from scrapy.selector import Selector
class MySpider(CrawlSpider):
name = "craig"
allowed_domains = ["craigslist.org"]
start_urls = ["http://sfbay.craigslist.org/search/npo"]
rules = (
Rule(LxmlLinkExtractor(
restrict_xpaths=(".//*[@id='sortable-results']//li//a")),
follow=False,
callback='parse_item'
),
)
def parse_item(self, response):
sel = Selector(response)
item = CraigslistSampleItem()
item['title'] = sel.xpath('//*[@id="titletextonly"]').extract_first()
item['body'] = sel.xpath('//*[@id="postingbody"]').extract_first()
item['link'] = response.url
yield item
Run Code Online (Sandbox Code Playgroud)
克雷格/ items.py
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
from scrapy.item import Item, Field
class CraigslistSampleItem(Item):
title = Field()
body = Field()
link = Field()
Run Code Online (Sandbox Code Playgroud)
克雷格/ settings.py
# -*- coding: utf-8 -*-
BOT_NAME = 'craig'
SPIDER_MODULES = ['craig.spiders']
NEWSPIDER_MODULE = 'craig.spiders'
ITEM_PIPELINES = {
'craig.pipelines.CraigPipeline': 300,
}
Run Code Online (Sandbox Code Playgroud)
克雷格/ pipelines.py
from scrapy import signals
from scrapy.xlib.pydispatch import dispatcher
from scrapy.exporters import CsvItemExporter
class CraigPipeline(object):
def __init__(self):
dispatcher.connect(self.spider_opened, signals.spider_opened)
dispatcher.connect(self.spider_closed, signals.spider_closed)
self.files = {}
def spider_opened(self, spider):
file = open('%s_ads.csv' % spider.name, 'w+b')
self.files[spider] = file
self.exporter = CsvItemExporter(file)
self.exporter.start_exporting()
def spider_closed(self, spider):
self.exporter.finish_exporting()
file = self.files.pop(spider)
file.close()
def process_item(self, item, spider):
self.exporter.export_item(item)
return item
Run Code Online (Sandbox Code Playgroud)
您可以通过运行命令来运行spider :
scrapy runspider scraper/spiders/spider.py
Run Code Online (Sandbox Code Playgroud)
从项目的根目录.
它应该craig_ads.csv
在项目的根目录中创建一个.
我正在尝试回答您的问题。
首先,由于您的XPath 查询不正确,您得到了空白结果。通过 XPath ".//*[@id='sortable-results']//ul//li//p"
,您<p>
正确定位了相关节点,但我不喜欢您的查询表达式。但是,我不知道您的以下 XPath 表达式".//*[@id='titletextonly']"
和"a/@href"
,他们无法按您的预期找到链接和标题。也许你的意思是定位标题的文本和标题的超链接。如果是的话,我相信你必须学习 Xpath,并且请从HTML DOM开始。
我确实想指导您如何进行 XPath 查询,因为网上有很多资源。我想提一下 Scrapy XPath 选择器的一些特性:
在标准 XPath 查询中,它返回您查询的 DOM 节点数组。您可以打开浏览器(F12
)的开发模式,使用控制台命令$x(x_exp)
进行测试。我强烈建议通过这种方式测试您的 XPath 表达式。它将为您提供即时结果并节省大量时间。如果有时间,熟悉一下浏览器的web开发工具,可以让你快速了解网页结构,找到你要找的入口。
而 Scrapyresponse.xpath(x_exp)
返回一个Selector
对应于实际 XPath 查询的对象数组,它实际上是一个SelectorList
对象。这意味着 XPath 结果由SelectorsList
. 并且classSelector
和SelectorList
class 都提供了一些有用的函数来操作结果:
extract
, 返回序列化文档节点列表(以 unicode 字符串)extract_first
,返回标,first
对的extract
结果re
,返回一个列表,re
该的extract
结果re_first
,返回标,first
对的re
结果。这些功能使您的编程更加方便。一个例子是你可以xpath
直接在SelectorList
对象上调用函数。如果您lxml
之前尝试过,您会发现这非常有用:如果您想对xpath
前一个xpath
结果的结果调用函数,则lxml
必须迭代前一个结果。另一个例子是,当您确定该列表中最多只有一个元素时,您可以使用extract_first
获取一个标量值,而不是使用列表索引方法(例如,rlist[0]
),当没有元素匹配时,它会导致索引外异常。请记住,解析网页时总会有例外,请谨慎并健壮地编程。
请记住,如果您正在嵌套 XPathSelector 并使用以 / 开头的 XPath,则该 XPath 将是文档的绝对路径,而不是相对于您从中调用它的 XPathSelector。
操作时node.xpath(x_expr)
,如果x_expr
以 开头/
,则为绝对查询,XPath 会从开始搜索root
;else 如果x_expr
以 开头.
,则是相对查询。这也在标准2.5 Abbreviated Syntax 中注明
. 选择上下文节点
.//para 选择上下文节点的para元素后代
.. 选择上下文节点的父节点
../@lang 选择上下文节点的父级的lang属性
对于您的应用程序,您可能需要遵循下一页。在这里,下一个页面节点很容易找到——有下一个按钮。但是,您还需要注意停止关注的时间。仔细查看您的 URL 查询参数以了解应用程序的 URL 模式。在这里,要确定何时停止关注下一页,您可以将当前项目范围与项目总数进行比较。
新编辑
我对链接内容的含义有点困惑。现在我知道@student 也想抓取链接以提取 AD 内容。下面是一个解决方案。
您可能会注意到,我使用 ScrapyRequest
类来跟随下一页。实际上,Request类的功能不止于此——您可以通过设置参数为每个请求附加所需的解析函数callback
。
callback (callable) – 将使用此请求的响应(一旦下载)作为其第一个参数调用的函数。有关更多信息,请参阅下面的将附加数据传递给回调函数。如果请求未指定回调,则将使用蜘蛛的 parse() 方法。请注意,如果在处理期间引发异常,则会调用 errback。
在步骤 3 中,callback
发送下一页请求时我没有设置,因为这些请求应该由默认parse
函数处理。现在来到指定的 AD 页面,与之前的 AD 列表页面不同的页面。因此我们需要定义一个新的页面解析器函数,比方说parse_ad
,当我们发送每个 AD 页面请求时,将这个parse_ad
函数附加到请求中。
让我们转到对我有用的修改后的示例代码:
项目.py
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class ScrapydemoItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
link = scrapy.Field()
class AdItem(scrapy.Item):
title = scrapy.Field()
description = scrapy.Field()
Run Code Online (Sandbox Code Playgroud)
蜘蛛
# -*- coding: utf-8 -*-
from scrapy.spiders import Spider
from scrapy.http import Request
from scrapydemo.items import ScrapydemoItem
from scrapydemo.items import AdItem
try:
from urllib.parse import urljoin
except ImportError:
from urlparse import urljoin
class MySpider(Spider):
name = "demo"
allowed_domains = ["craigslist.org"]
start_urls = ["http://sfbay.craigslist.org/search/npo"]
def parse(self, response):
# locate list of each item
s_links = response.xpath("//*[@id='sortable-results']/ul/li")
# locate next page and extract it
next_page = response.xpath(
'//a[@title="next page"]/@href').extract_first()
next_page = urljoin(response.url, next_page)
to = response.xpath(
'//span[@class="rangeTo"]/text()').extract_first()
total = response.xpath(
'//span[@class="totalcount"]/text()').extract_first()
# test end of following
if int(to) < int(total):
# important, send request of next page
# default parsing function is 'parse'
yield Request(next_page)
for s_link in s_links:
# locate and extract
title = s_link.xpath("./p/a/text()").extract_first().strip()
link = s_link.xpath("./p/a/@href").extract_first()
link = urljoin(response.url, link)
if title is None or link is None:
print('Warning: no title or link found: %s', response.url)
else:
yield ScrapydemoItem(title=title, link=link)
# important, send request of ad page
# parsing function is 'parse_ad'
yield Request(link, callback=self.parse_ad)
def parse_ad(self, response):
ad_title = response.xpath(
'//span[@id="titletextonly"]/text()').extract_first().strip()
ad_description = ''.join(response.xpath(
'//section[@id="postingbody"]//text()').extract())
if ad_title is not None and ad_description is not None:
yield AdItem(title=ad_title, description=ad_description)
else:
print('Waring: no title or description found %s', response.url)
Run Code Online (Sandbox Code Playgroud)
重点说明
parse
用于AD列表页面parse_ad
的请求和指定AD页面的请求。输出快照:
2016-11-10 21:25:14 [scrapy] DEBUG: Scraped from <200 http://sfbay.craigslist.org/eby/npo/5869108363.html>
{'description': '\n'
' \n'
' QR Code Link to This Post\n'
' \n'
' \n'
'Agency History:\n' ........
'title': 'Staff Accountant'}
2016-11-10 21:25:14 [scrapy] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 39259,
'downloader/request_count': 117,
'downloader/request_method_count/GET': 117,
'downloader/response_bytes': 711320,
'downloader/response_count': 117,
'downloader/response_status_count/200': 117,
'finish_reason': 'shutdown',
'finish_time': datetime.datetime(2016, 11, 11, 2, 25, 14, 878628),
'item_scraped_count': 314,
'log_count/DEBUG': 432,
'log_count/INFO': 8,
'request_depth_max': 2,
'response_received_count': 117,
'scheduler/dequeued': 116,
'scheduler/dequeued/memory': 116,
'scheduler/enqueued': 203,
'scheduler/enqueued/memory': 203,
'start_time': datetime.datetime(2016, 11, 11, 2, 24, 59, 242456)}
2016-11-10 21:25:14 [scrapy] INFO: Spider closed (shutdown)
Run Code Online (Sandbox Code Playgroud)
谢谢。希望这会有所帮助并玩得开心。
归档时间: |
|
查看次数: |
5304 次 |
最近记录: |