爬虫scrapy

爬虫scrapy

点击这里还可以去我的博客主页o
点击这里还可以去大神的学习笔记o

前言

本页只是为了方便本人以后复习爬虫scrapy用的笔记markdown

纯属娱乐,如有雷同,打死不认——


  1. 开启scrapy之旅
  2. 常用的工具命令
  3. 项目开始以及连接mongodb
  4. scrapy选择器xpath和css选择器
  5. scrapy框架实现篇
  6. scrapy避免被禁止
  7. 自动爬取网页实战
  8. crawlspider快速抓取

开启scrapy之旅

1.安装好虚拟环境virtualenv scrapy_env
进入scripts然后activate进入虚拟
2.下载相应的包
分别是顺序pip intsall
wheel,lxml,PyOpenssl,Twisted,Pywin32,Scrapy
3.开始scrapy项目 scrapy startproject quote
4.然后scrapy genspider quotes quotes.toscrape.com
打开pycharm打开相应文件夹,里面就是这个项目quote,里面有同名quote然后里面spiders还有自己创建的quotes

遇到的问题
因为创建了quote再pychram里面打开终端就直接打开了quote一个虚拟环境,然后执行scrapy怎样都是'scrapy' 不是内部或外部命令,也不是可运行的程序
百度半天说没有加入path,然后我吧D:Python_codescrapy_envScripts加入环境了后发现进入quote这个虚拟也不行,'scrapy' 不是内部或外部命令,也不是可运行的程序,然后我想起来,这个是虚拟环境,加入path也不能进入这个虚拟,所以我退出虚拟quote,deactivate进入scrapy_env的虚拟即scrapy的安装虚拟路径和环境再执行,ok了
点击这里还可以去scrapy官方文档
点击这里去教程scrapy菜鸟教程


常用的工具命令

scrapy 中常用的工具分两种1是全局命令,2是项目命令
全局命令就是不依靠Scrapy就能直接运行,而项目命令就是需要在项目中才能运行
1全局命令 我们可以通过scrapy -h直接查看所有的全局命令
2项目命令基于项目使用,进入项目才能使用


解析quote scrapy

第一是进入scrapy_env的虚拟,因为我的scrapy和一系列的包都在这个虚拟下载的,不是在全局下载的,当时pip的时候就在虚拟pip,这样呢以后每个项目都能用scrapy的包啊虚拟这些,麻烦的就是每次需要在终端进入这个虚拟才行

首先在item中定义好数据
class QuoteItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    text=scrapy.Field()
    author=scrapy.Field()
    tags=scrapy.Field()
然后在spiders目录下的quotes中
    def parse(self, response):
        quotes=response.css('.quote')#.quote是pyquery的特点
        for quote in quotes.css('.text::text').extract_frist():
           item=QuoteItem()
            text=quote.css('.text::text').extract_frist()
            author=quote.css('.author::text').extract_frist()
            tags=quote.css('.tags .tag::text').extract()  #所有结果,多个内容,类似于findall
            item['text'] = text
            item['author']=author
            item['tags']=tags
            yield item
        next =response.css('.pager .next a::attr(href)').extract_first()  #这个是参看f12里面下一页按钮那里的的 是两个class
        url=response.urljoin(next) #urljoin是一个方法,可以生成一个完整的url因为是不完整的比如少http://等
        yield scrapy.Request(url=url,callback=self.parse)  #递归,自己回调自己

解释下.quote .text这是一种css的选择方式而::text则是scrapy的方式,表示输出data的字符串,而直接用.css的话输出为标签,
extract表示输出返回的是一个列表,_frist则就是输出第一个标签没有frist就算全部
然后在终端,如果在Shell因为我一开始写了命令crapy shell quotes.toscrapy.com进入了这个交互环境中,所以执行exit()先退到scrapy_env的虚拟当中再执行scrapy crawl quotes(quotes是那个文件夹名)就 ok了
如果最后执行 scrapy crawl quotes没问题后要想保存数据可以scrapy crawl quotes -0 quotes.json就保存为json格式了同样的其他格式也是这样比如scrapy crawl quotes -0 quotes.csv等就会发现有这个文件了,里面数据也在里面格式也更加清楚
在pipeline里面
from scrapy.exceptions import DropItem
import pymongo

class TextPipeline(object):
    def __init__(self):
        self.limit=50
    def process_item(self, item, spider):
        if item['text']:
            if len (item['text'])>self.limit:
                item['text']=item['text'][0:self.limit].rstrip()+'........' #rstrip去除空格
                return item
            else:
                return DropItem('miss Text')

class mongopipeline(object):
    def __init__(self,mongo_url,mongo_db):
        self.mongo_url=mongo_url
        self.mongo_db=mongo_db

    @classmethod
    def from_crawler(cls,crawler):
        return cls(
            mongo_url=crawler.setting.get('MONGO_URL'),
            mongo_db=crawler.setting.get('MONGO_DB'),
        )
    def open_spider(self,spider):
        self.client=pymongo.MongoClient(self.mongo_url)
        self.db=self.client(self.mongo_db)

    def process_item(self,item,spider):
        name=item.__class__.__name__
        self.db[name].insert(dict(item))
        return item

    def close_spider(self,spider):
        self.client.close()
而我的电脑连接mongodb两种方法 ,第一种直接用命令mongod--dbpath E:data或者直接搜索服务找到mondodb server 打开即可
而且在MongoDB中经常我错的地方就是
修改完成后的代码:
client = pymongo.MongoClient('localhost')
db = client['my_database']#注意这里用中括号!!
不然总会'MongoClient' object is not callable

xpath和css选择器


我们将在下面的例子中使用这个 XML 文档。

<?xml version="1.0" encoding="ISO-8859-1"?>

<bookstore>

<book>
  <title lang="eng">Harry Potter</title>
  <price>29.99</price>
</book>

<book>
  <title lang="eng">Learning XML</title>
  <price>39.95</price>
</book>

</bookstore>
选取节点
XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。

下面列出了最有用的路径表达式:
表达式	描述
nodename	选取此节点的所有子节点。
/	从根节点选取。
//	从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
.	选取当前节点。
..	选取当前节点的父节点。
@	选取属性。
实例
在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:

路径表达式	结果
bookstore	选取 bookstore 元素的所有子节点。
/bookstore	
选取根元素 bookstore。

注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!

bookstore/book	选取属于 bookstore 的子元素的所有 book 元素。
//book	选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book	选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang	选取名为 lang 的所有属性。
谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点。

谓语被嵌在方括号中。

实例
在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:

路径表达式	结果
/bookstore/book[1]	选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()]	选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1]	选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3]	选取最前面的两个属于 bookstore 元素的子元素的 book 元素。

//title[@lang]	选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang='eng']	选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00]	选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title	选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。
选取未知节点
XPath 通配符可用来选取未知的 XML 元素。
/html/body/h2/text() 即 提取出h2便签的内容
使用//可以提取某个标签的所有信息
//p 选取所有p标签的所有信息
加入很多段 <img src='......' class='f1'>
这时
//img[@class='f1']就是获取所有class属性值为f1的<img>标签的内容
通配符	描述
*	匹配任何元素节点。
@*	匹配任何属性节点。
node()	匹配任何类型的节点。
实例
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式	结果
/bookstore/*	选取 bookstore 元素的所有子元素。
//*	选取文档中的所有元素。
//title[@*]	选取所有带有属性的 title 元素。
选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。

实例
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式	结果
//book/title | //book/price	选取 book 元素的所有 title 和 price 元素。
//title | //price	选取文档中的所有 title 和 price 元素。
/bookstore/book/title | //price	选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。
scrapy中的css选择器语法
*
所有节点
#container
选择id为container的节点
.container
选择class为container的节点
li a
选择所有li下的所有a节点
ul + p
选择ul后的第一个p节点
div#container > ul
选择id为container的div的第一个ul子节点
ul ~ p
选取与ul相邻的所有的p元素
a[title]
选取所有包含有title属性的a元素
a[href="http://jobbole.com"]
选取所有href属性为jobbole.com的a元素
a[href*="jobbole"]
选取所有href属性包含jobbole的a元素
a[href^="http"]
选取所有href属性以http开头的a元素
a[href$=".jpt"]
选取所有href属性以.jpg结尾的a元素
input[type=radio]:checked
选取选中的radio元素
div:not(#container)
选取所有id不为container的div元素
li:nth-child(3)
选取第三个li元素
tr:nth-child(2n)
第偶数个tr

scrapy选择器实战

Scrapy选择器构建于 lxml 库之上,这意味着它们在速度和解析准确性上非常相似。
我们将使用 Scrapy shell
(提供交互测试)和位于Scrapy文档服务器的一个样例页面,来解释如何使用选择器:
http://doc.scrapy.org/en/latest/_static/selectors-sample1.html


这里是它的HTML源码:
<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html'>Name: My image 1 <br />![](image1_thumb.jpg)</a>
   <a href='image2.html'>Name: My image 2 <br />![](image2_thumb.jpg)</a>
   <a href='image3.html'>Name: My image 3 <br />![](image3_thumb.jpg)</a>
   <a href='image4.html'>Name: My image 4 <br />![](image4_thumb.jpg)</a>
   <a href='image5.html'>Name: My image 5 <br />![](image5_thumb.jpg)</a>
  </div>
 </body>
</html>

3.1 构造选择器
首先, 我们打开shell:
scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html


接着,当shell载入后,您将获得名为response
的shell变量,其为响应的response, 并且在其 response.selector属性上绑定了一个 selector。
因为我们处理的是HTML,选择器将自动使用HTML语法分析。
那么,通过查看 HTML code 该页面的源码,我们构建一个XPath来选择title标签内的文字:

>>> response.selector.xpath('//title/text()')
[<Selector (text) xpath=//title/text()>]


由于在response中使用XPath、CSS查询十分普遍,因此,Scrapy提供了两个实用的快捷方式: response.xpath() 及 response.css():

>>> response.xpath('//title/text()')
[<Selector (text) xpath=//title/text()>]
>>> response.css('title::text')
[<Selector (text) xpath=//title/text()>]


如你所见, .xpath()及 .css()方法返回一个类 SelectorList 的实例, 它是一个新选择器的列表。这个API可以用来快速的提取嵌套数据。
为了提取真实的原文数据,你需要调用 .extract()方法如下:

>>> response.xpath('//title/text()').extract()
[u'Example website']


如果想要提取到第一个匹配到的元素, 必须调用 .extract_first()  selector:

>>> response.xpath('//div[@id="images"]/a/text()').extract_first()
u'Name: My image 1 '


现在我们将得到根URL(base URL)和一些图片链接:

>>> response.xpath('//base/@href').extract()
[u'http://example.com/']

>>> response.css('base::attr(href)').extract()
[u'http://example.com/']

>>> response.xpath('//a[contains(@href, "image")]/@href').extract()
[u'image1.html',
 u'image2.html',
 u'image3.html',
 u'image4.html',
 u'image5.html']

>>> response.css('a[href*=image]::attr(href)').extract()
[u'image1.html',
 u'image2.html',
 u'image3.html',
 u'image4.html',
 u'image5.html']

>>> response.xpath('//a[contains(@href, "image")]/img/@src').extract()
[u'image1_thumb.jpg',
 u'image2_thumb.jpg',
 u'image3_thumb.jpg',
 u'image4_thumb.jpg',
 u'image5_thumb.jpg']

>>> response.css('a[href*=image] img::attr(src)').extract()
[u'image1_thumb.jpg',
 u'image2_thumb.jpg',
 u'image3_thumb.jpg',
 u'image4_thumb.jpg',
 u'image5_thumb.jpg']

3.2选择器嵌套

选择器方法( .xpath() or .css() )返回相同类型的选择器列表,因此你也可以对这些选择器调用选择器方法。下面是一个例子:

>>> links = response.xpath('//a[contains(@href, "image")]')
>>> links.extract()
[u'<a href="image1.html">Name: My image 1 <br>![](image1_thumb.jpg)</a>',
 u'<a href="image2.html">Name: My image 2 <br>![](image2_thumb.jpg)</a>',
 u'<a href="image3.html">Name: My image 3 <br>![](image3_thumb.jpg)</a>',
 u'<a href="image4.html">Name: My image 4 <br>![](image4_thumb.jpg)</a>',
 u'<a href="image5.html">Name: My image 5 <br>![](image5_thumb.jpg)</a>']

>>> for index, link in enumerate(links):
        args = (index, link.xpath('@href').extract(), link.xpath('img/@src').extract())
        print 'Link number %d points to url %s and image %s' % args

Link number 0 points to url [u'image1.html'] and image [u'image1_thumb.jpg']
Link number 1 points to url [u'image2.html'] and image [u'image2_thumb.jpg']
Link number 2 points to url [u'image3.html'] and image [u'image3_thumb.jpg']
Link number 3 points to url [u'image4.html'] and image [u'image4_thumb.jpg']
Link number 4 points to url [u'image5.html'] and image [u'image5_thumb.jpg']

3.3 结合正则表达式使用选择器(selectors)

Selector 也有一个 .re()方法,用来通过正则表达式来提取数据。然而,不同于使用 .xpath() 或者 .css() 方法, .re() 方法返回unicode字符串的列表。所以你无法构造嵌套式的 .re() 调用。
下面是一个例子,从上面的 HTML code 中提取图像名字:

>>> response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:s*(.*)')
[u'My image 1',
 u'My image 2',
 u'My image 3',
 u'My image 4',
 u'My image 5']


另外还有一个糅合了 .extract_first() 与 .re() 的函数 .re_first() . 使用该函数可以提取第一个匹配到的字符串:

>>> response.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:s*(.*)')
u'My image 1'


scrapy框架实现篇

创建一个项目scrapy startproject name
Items实战

进入items 其实items就是容器,保存爬取的数据,储蓄作用
创建的items会加上你项目的名称自动创建类
如
class HellScrapyItem(scrapy.Item):#继承scrapy下的Item类
    # define the fields for your item here like:
    # name = scrapy.Field()
    urlname=scrapy.Field()
    urlkey=scrapy.Field()
    urlcr=scrapy.Field()
    urladdr=scrapy.Field()
这个类里面定义结构化数据,即将scrapy下的Field类实例化
然后我们要用的时候实例化这个类就可以了
如:weisuen=person(urlname='weiwei',urlkey='123',urlcr='sdda',urladdr='asd')
然后print(weisuen)就有了

parse方法
默认的回调函数
就是很多函数返回的时候有一个callback=
就是这个


Spider编写

scrapy.spiders.Spider
这是最简单的蜘蛛,也是每个其他蜘蛛必须继承的蜘蛛(包括与Scrapy捆绑在一起的蜘蛛,以及你自己编写的蜘蛛)。它不提供任何特殊功能。它只提供了一个默认start_requests()实现,它从start_urlsspider属性发送请求,并parse 为每个结果响应调用spider的方法。

而我们可以通过项目中运行genspider命令创建一个爬虫文件
scrapy genspider weisuen iqianyue.com
然后就有一个weisuen.py在spiders文件下
并且已经自动生成了下面代码
class WeisuenSpider(scrapy.Spider):
    name = 'weisuen'
    allowed_domains = ['iqianyue.com']
    start_urls = ['http://iqianyue.com/']

    def parse(self, response):
        pass
这个名为parse的方法是处理scrapy爬虫爬行到网页响应的默认方法,如果有特别指定的回调函数就不用这个,一般默认这个,由自己编写,
同时该方法也负责链接的跟进
    def parse(self, response):
        item=HellScrapyItem()
        item['urlname']=response.xpath('/html/head/title/text()')
        print(item['urlname'])
        然后执行scrapy crawl weisuen就会打印出来开头的文字
        [<Selector xpath='/html/head/title/text()' data='千月枫痕_遇见更文艺的你_千月枫痕'>]
就OK了
除了parse,Scrapy的Spider中常见的属性和方法还有

make_requests_from_url(url)
该方法被start_requests()调用,实现生成Request请求对象,回调默认的是parse()函数,当然也可以回调指定函数如
def make_requests_from_url(self,url):
    return scrapy.Request(url=url,callback=self.parse_index)
def parse_index(self,response):
    print('Baidu',response.status)

start_requests()
该方法默认读取start_url属性中定义的网址,并为每个网址生成一个Request请求对象,并返回迭代对象,当然也可以不用start_url中的网址,也可以自定义
如
import scrapy
from hell_scrapy.items import HellScrapyItem

class WeisuenSpider(scrapy.Spider):
    name = 'weisuen'
    allowed_domains = ['iqianyue.com']
    start_urls = ['http://iqianyue.com/']
    urls2=(
        'http://www.jd.com',
        'http://sina.com.cn',
        'http://yum.iqianyue.com',
    )
    def start_requests(self):
        for url in self.urls2:
            yield self.make_requests_from_url(url)
            
            
    def parse(self, response):
        item=HellScrapyItem()
        item['urlname']=response.xpath('/html/head/title/text()')
        print(item['urlname'])
        这样的话我们的start_urls其实是没有作用的
        如输出答案为
        [<Selector xpath='/html/head/title/text()' data='京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物!'>]
        [<Selector xpath='/html/head/title/text()' data='新浪首页'>]
        [<Selector xpath='/html/head/title/text()' data='韬云科技|国内首家企业专属云平台'>]
    
    还可以这样
    start_requests(self):
    yield scrapy.Request(url='http://www.baidu.com',callback=self.parse.index)
    指定url或者一个url列表函数


__init__()
该方法主要负责爬虫的初始化,为构造函数
当然在传参时它的作用也无比明显

allowed_domains是允许的域名,当有很多允许域名而又懒的添加时可以删去。
这些都可以在上面的连接点开教程看
    现在让我们看看我们的蜘蛛被修改为递归地跟随到下一页的链接,从中提取数据:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)
            现在,在提取数据之后,该parse()方法查找到下一页的链接,使用该urljoin()方法构建完整的绝对URL (因为链接可以是相对的)并向下一页生成新请求,将自身注册为回调处理下一页的数据提取并保持爬网遍历所有页面。

你在这里看到的是Scrapy跟踪链接的机制:当你在回调方法中产生一个Request时,Scrapy会安排发送该请求并注册一个回调方法,以便在该请求完成时执行。

使用此功能,您可以根据您定义的规则构建跟踪链接的复杂爬网程序,并根据其访问的页面提取不同类型的数据。

在我们的示例中,它创建了一种循环,跟随到下一页的所有链接,直到它找不到 - 用于爬行博客,论坛和其他具有分页的网站。
创建请求的快捷方式
作为创建Request对象的快捷方式,您可以使用 response.follow:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('span small::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)
与scrapy.Request不同,它response.follow直接支持相对URL - 无需调用urljoin(urljoin是构造方法前面)。
绝对URL,就是总是以域名(或者/)开头的网址就是"绝对URL"。
注释:"/"代表域名对应的网站根目录。
例如:http://www.baidu.com/image/baobao.gif。注意,response.follow只返回一个Request实例; 你仍然需要提出这个请求。

您也可以传递选择器response.follow而不是字符串; 此选择器应提取必要的属性:

for href in response.css('li.next a::attr(href)'):
    yield response.follow(href, callback=self.parse)
对于<a>元素,有一个快捷方式:response.follow自动使用其href属性。所以代码可以进一步缩短:

for a in response.css('li.next a'):
    yield response.follow(a, callback=self.parse)
注意
response.follow(response.css('li.next a'))无效
是因为 response.css返回一个类似于列表的对象,其中包含所有结果的选择器,而不是单个选择器。甲for象在上面的例子中循环,或 是好的。response.follow(response.css('li.next a')[0])

更多示例和模式
import scrapy
class AuthorSpider(scrapy.Spider):
    name = 'author'
    start_urls = ['http://quotes.toscrape.com/']
    def parse(self, response):
        # follow links to author pages
        for href in response.css('.author + a::attr(href)'):
            yield response.follow(href, self.parse_author)

        # follow pagination links
        for href in response.css('li.next a::attr(href)'):
            yield response.follow(href, self.parse)

    def parse_author(self, response):
        def extract_with_css(query):
            return response.css(query).get(default='').strip()

        yield {
            'name': extract_with_css('h3.author-title::text'),
            'birthdate': extract_with_css('.author-born-date::text'),
            'bio': extract_with_css('.author-description::text'),
        }
        这个蜘蛛将从主页面开始,它将跟随作者页面的所有链接,parse_author为每个页面调用回调,以及parse我们之前看到的与回调的分页链接。这里我们将回调传递给response.follow位置参数以使代码更短; 它也适用于scrapy.Request。
该parse_author回调定义了一个辅助函数从CSS查询提取和清理数据,并产生了Python字典与作者的数据。
这个蜘蛛演示的另一个有趣的事情是,即使同一作者有很多引用,我们也不必担心多次访问同一个作者页面。默认情况下,Scrapy会筛选出已访问过的URL的重复请求,从而避免因编程错误而导致服务器过多的问题。这可以通过设置进行配置 DUPEFILTER_CLASS
        这个简而言之就是
开始 进入第一个for循环一直将页面里的作者信息链接提取出来,通过follow方法生成Request再回调parser_author函数这样一直到这一页的作者链接完毕,然后下一个for循环 即下一页。
就如前面所言。当你在回调方法中产生一个Request时,Scrapy会安排发送该请求并注册一个回调方法,以便在该请求完成时执行。
传参
import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def start_requests(self):
        url = 'http://quotes.toscrape.com/'
        tag = getattr(self, 'tag', None)
        if tag is not None:
            url = url + 'tag/' + tag
        yield scrapy.Request(url, self.parse)

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
            }

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)
如果您将tag=humor参数传递给此蜘蛛,您会注意到它只会访问humor标记中的URL ,例如 http://quotes.toscrape.com/tag/humor。

蜘蛛可以在__init__方法中访问参数:

import scrapy

class MySpider(scrapy.Spider):
    name = 'myspider'

    def __init__(self, category=None, *args, **kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.start_urls = ['http://www.example.com/categories/%s' % category]
        # ...
通用蜘蛛
Scrapy附带了一些有用的通用蜘蛛,您可以使用这些蜘蛛来对您的蜘蛛进行子类化。他们的目的是为一些常见的抓取案例提供方便的功能,例如根据特定规则跟踪站点上的所有链接,从站点地图抓取或解析XML / CSV Feed。

对于以下蜘蛛中使用的示例,我们假设您有一个TestItem在myproject.items模块中声明的项目:

import scrapy

class TestItem(scrapy.Item):
    id = scrapy.Field()
    name = scrapy.Field()
    description = scrapy.Field()
抓取蜘蛛
类scrapy.spiders.CrawlSpider
这是用于抓取常规网站的最常用的蜘蛛,因为它通过定义一组规则为跟踪链接提供了便利的机制。它可能不是最适合您的特定网站或项目,但它在几种情况下足够通用,因此您可以从它开始并根据需要覆盖它以获得更多自定义功能,或者只是实现您自己的蜘蛛。

除了从Spider继承的属性(您必须指定)之外,此类还支持一个新属性:

rules
这是一个(或多个)Rule对象的列表。每个都Rule 定义了爬网站点的特定行为。规则对象如下所述。如果多个规则匹配相同的链接,则将根据它们在此属性中定义的顺序使用第一个规则。

这个蜘蛛还暴露了一个可重写的方法:

parse_start_url(回应)
为start_urls响应调用此方法。它允许解析初始响应,并且必须返回 Item对象,Request 对象或包含其中任何一个的iterable。

爬行规则
class scrapy.spiders.Rule(link_extractor,callback = None,cb_kwargs = None,follow = None,process_links = None,process_request = None )
link_extractor是一个Link Extractor对象,它定义如何从每个已爬网页面中提取链接。

callback是一个可调用的或一个字符串(在这种情况下,将使用来自具有该名称的spider对象的方法)为使用指定的link_extractor提取的每个链接调用。此回调接收响应作为其第一个参数,并且必须返回包含Item和/或 Request对象(或其任何子类)的列表。

        
CrawlSpider示例
现在让我们看看带有规则的示例CrawlSpider:

import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class MySpider(CrawlSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com']

    rules = (
        # Extract links matching 'category.php' (but not matching 'subsection.php')
        # and follow links from them (since no callback means follow=True by default).
        Rule(LinkExtractor(allow=('category.php', ), deny=('subsection.php', ))),

        # Extract links matching 'item.php' and parse them with the spider's method parse_item
        Rule(LinkExtractor(allow=('item.php', )), callback='parse_item'),
    )

    def parse_item(self, response):
        self.logger.info('Hi, this is an item page! %s', response.url)
        item = scrapy.Item()
        item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (d+)')
        item['name'] = response.xpath('//td[@id="item_name"]/text()').get()
        item['description'] = response.xpath('//td[@id="item_description"]/text()').get()
        return item
这个蜘蛛会开始抓取example.com的主页,收集类别链接和项链接,使用该parse_item方法解析后者。对于每个项目响应,将使用XPath从HTML中提取一些数据,并将Item使用它填充。

XMLFeedSpider 
而怎样创建呢
scrapy genspider -l
就能看到一系列
再通过scrapy genspider -t xmlfeed [name] [域名]
j就可以了
而且xmlfeedspider自带parse_node就像自带的普通爬虫项目的parse一样
类scrapy.spiders.XMLFeedSpider
XMLFeedSpider用于通过按某个节点名称迭代XML feed来解析XML feed。迭代器可以选自:iternodes,xml,和html。iternodes出于性能原因,建议使用迭代器,因为xml和html迭代器一次生成整个DOM以便解析它。但是,在使用html错误标记解析XML时,使用迭代器可能很有用。

要设置迭代器和标记名称,必须定义以下类属性:

iterator
一个字符串,它定义要使用的迭代器。它可以是:

'iternodes' - 基于正则表达式的快速迭代器
'html'- 使用的迭代器Selector。请记住,这使用DOM解析,并且必须在内存中加载所有DOM,这可能是大型Feed的问题
'xml'- 使用的迭代器Selector。请记住,这使用DOM解析,并且必须在内存中加载所有DOM,这可能是大型Feed的问题
它默认为:'iternodes'。

itertag
一个字符串,其中包含要迭代的节点(或元素)的名称。示例:

itertag = 'product'
namespaces
一个元组列表,用于定义将使用此spider处理的该文档中可用的名称空间。的 和将被用于自动注册使用的命名空间 的方法。(prefix, uri)prefixuriregister_namespace()

然后,您可以在itertag 属性中指定具有名称空间的节点。

例:

class YourSpider(XMLFeedSpider):

    namespaces = [('n', 'http://www.sitemaps.org/schemas/sitemap/0.9')]
    itertag = 'n:url'
    # ...
除了这些新属性外,此蜘蛛还具有以下可重写方法:

adapt_response(回应)
在蜘蛛开始解析之前,一旦从蜘蛛中间件到达就接收响应的方法。它可以在解析之前用于修改响应主体。此方法接收响应并返回响应(可能是相同或另一个)。

parse_node(响应,选择器)
对于与提供的标记名称(itertag)匹配的节点,调用此方法。接收Selector每个节点的响应和响应 。必须覆盖此方法。否则,你的蜘蛛将无法正常工作。此方法必须返回Item对象, Request对象或包含其中任何对象的iterable。

process_results(回应,结果)
为蜘蛛返回的每个结果(项目或请求)调用此方法,并且它旨在执行将结果返回到框架核心之前所需的任何上次处理,例如设置项目ID。它会收到一个结果列表以及产生这些结果的响应。它必须返回结果列表(项目或请求)。

XMLFeedSpider示例
这些蜘蛛很容易使用,让我们来看一个例子:
class MyxmlspiderSpider(XMLFeedSpider):
    name = 'myxmlspider'
    allowed_domains = ['sina.com.cn']
    start_urls = ['http://blog.sina.com.cn/rss/1615888477.xml']
    iterator = 'iternodes' # you can change this; see the docs
    itertag = 'rss' # change it accordingly

    def parse_node(self, response, node):
        # item = {}
        i=MyxmlItem()#在item里面定义好了的
        #item['url'] = selector.select('url').get()
        #item['name'] = selector.select('name').get()
        #item['description'] = selector.select('description').get()
        i['title']=node.xpath('/rss/channel/item/title/text()').extract()
        i['link']=node.xpath('rss/channel/item/link/text()').extract()
        i['author']=node.xpath('rss/channel/item/author/text()').extract()
        for j in range(len(i['title'])):
            print('第'+str(j+1)+'篇文章')
            print('标题是:')
            print(i['title'][j])
            print('对应的链接是:')
            print(i['link'][j])
            print('对应的作者是:')
            print(i['author'][j])
            print('===============')
        return i



from scrapy.spiders import XMLFeedSpider
from myproject.items import TestItem

class MySpider(XMLFeedSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com/feed.xml']
    iterator = 'iternodes'  # This is actually unnecessary, since it's the default value
    itertag = 'item'

    def parse_node(self, response, node):
        self.logger.info('Hi, this is a <%s> node!: %s', self.itertag, ''.join(node.getall()))

        item = TestItem()
        item['id'] = node.xpath('@id').get()
        item['name'] = node.xpath('name').get()
        item['description'] = node.xpath('description').get()
        return item
基本上我们在那里做的是创建一个蜘蛛,从给定的下载源start_urls,然后遍历每个item标签,打印出来,并存储一些随机数据Item。

CSVFeedSpider 
类scrapy.spiders.CSVFeedSpider
这个蜘蛛与XMLFeedSpider非常相似,只不过它遍历行而不是节点。在每次迭代中调用的方法是parse_row()。

delimiter
CSV文件中每个字段的分隔符字符串默认为','(逗号)。

quotechar
带有CSV文件中每个字段的机箱字符的字符串默认为'"'(引号)。

headers
CSV文件中的列名列表。

parse_row(响应,行)
使用CSV文件的每个提供(或检测到的)标头的密钥接收响应和dict(表示每行)。该蜘蛛还提供了覆盖adapt_response和process_results用于预处理和后处理目的的方法的机会。

CSVFeedSpider示例
scrapy genspider -t csvfeed mycsvspider iqianyue.com
让我们看一个与前一个类似的示例,但使用 CSVFeedSpider:

from scrapy.spiders import CSVFeedSpider
from myproject.items import TestItem

class MySpider(CSVFeedSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com/feed.csv']
    delimiter = ';'
    quotechar = "'"
    headers = ['id', 'name', 'description']

    def parse_row(self, response, row):
        self.logger.info('Hi, this is a row!: %r', row)

        item = TestItem()
        item['id'] = row['id']
        item['name'] = row['name']
        item['description'] = row['description']
        return item
在项目之间共享根目录
项目根目录(包含该目录的目录)scrapy.cfg可以由多个Scrapy项目共享,每个项目都有自己的设置模块。

在这种情况下,你必须定义下这些设置模块的一个或多个别名[settings]在您的scrapy.cfg文件:

[settings]
default = myproject1.settings
project1 = myproject1.settings
project2 = myproject2.settings
默认情况下,scrapy命令行工具将使用这些default设置。使用SCRAPY_PROJECT环境变量指定scrapy要使用的其他项目:

$ scrapy settings --get BOT_NAME
Project 1 Bot
$ export SCRAPY_PROJECT=project2
$ scrapy settings --get BOT_NAME
Project 2 Bot

项目管道
点击这里还可以去笔记o
这个主要参看这个笔记 ,里面有源码

在一个项目被蜘蛛抓取后,它被发送到项目管道,该项目管道通过顺序执行的几个组件处理它。

每个项目管道组件(有时简称为“项目管道”)是一个实现简单方法的Python类。他们收到一个项目并对其执行操作,同时决定该项目是否应继续通过管道或被丢弃并且不再处理。

项目管道的典型用途是:

清理HTML数据
验证已删除的数据(检查项目是否包含某些字段)
检查重复项(并删除它们)
将已删除的项目存储在数据库中
process_item(self, item, spider)
处理item
open_spider(self, spider)
打开蜘蛛时会调用此方法。
如
from scrapy.exceptions import DropItem
import pymongo

class TextPipeline(object):
    def __init__(self):
        self.limit=50

    def process_item(self, item, spider):
        if item['text']:
            if len(item['text'])>self.limit:
                item['text']=item['text'][0:self.limit].rstrip()+'........' #rstrip去除空格
                return item
            else:
                return DropItem('miss Text')

#官网里有这些代码
class MongoPipeline(object):
    def __init__(self,mongo_url,mongo_db):
        self.mongo_url=mongo_url
        self.mongo_db=mongo_db

    @classmethod
    def from_crawler(cls,crawler):
        return cls(
            mongo_url=crawler.settings.get('MONGO_URL'),
            mongo_db=crawler.settings.get('MONGO_DB')
        )
    def open_spider(self,spider):
        self.client=pymongo.MongoClient(self.mongo_url)
        self.db=self.client[self.mongo_db]

    def process_item(self,item,spider):
        name=item.__class__.__name__
        self.db[name].insert(dict(item))
        return item

    def close_spider(self,spider):
        self.client.close()
并设置好setting 
        ITEM_PIPELINES = {
    'quote.pipelines.TextPipeline': 300,
    'quote.pipelines.MongoPipeline': 400
}
spiders下面与init同级添加一个yuotes.py
import scrapy
from quote.items import QuoteItem

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response):
        quotes=response.css('.quote')         #.quote是pyquery的特点
        for quote in quotes:
            item=QuoteItem()
            text=quote.css('.text::text').extract_first()
            author=quote.css('.author::text').extract_first()
            tags=quote.css('.tags .tag::text').extract()  #所有结果,多个内容,类似于findall
            item['text'] = text
            item['author']=author
            item['tags']=tags
            yield item
        next =response.css('.pager .next a::attr(href)').extract_first()  #这个可以参看f12里面的 是两个class
        url=response.urljoin(next) #可以生成一个完整的url因为是不完整的比如少http://等
        yield scrapy.Request(url=url,callback=self.parse)  #递归,自己回调自己
items里
class QuoteItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    text=scrapy.Field()
    author=scrapy.Field()
    tags=scrapy.Field()

download  middlewer
点击这里[downloader主页](https://docs.scrapy.org/en/latest/topics/downloader-middleware.html "崔庆才")o
download  middlewer
点击这里[downloader崔庆才视频](https://www.bilibili.com/video/av19057145/?p=28 "崔庆才")o

Scrapy批量运行爬虫文件的两种方法:

1、使用CrawProcess实现

https://doc.scrapy.org/en/latest/topics/practices.html

2、修改craw源码+自定义命令的方式实现
crawl命令的源码文件在scrapy官方的github项目中找到(地址是:https://github.com/scrapy/scrapy/blob/master/scrapy/commands/crawl.py

(1)我们打开scrapy.commands.crawl.py 文件可以看到:

    def run(self, args, opts):
        if len(args) < 1:
            raise UsageError()
        elif len(args) > 1:
            raise UsageError("running 'scrapy crawl' with more than one spider is no longer supported")
        spname = args[0]
 
        self.crawler_process.crawl(spname, **opts.spargs)
        self.crawler_process.start()
这是crawl.py 文件中的run() 方法,在此可以指定运行哪个爬虫,要运行所有的爬虫,则需要更改这个方法。

run() 方法中通过crawler_process.crawl(spname, **opts.spargs) 实现了爬虫文件的运行,spname代表爬虫名。要运行多个爬虫文件,首先要获取所有的爬虫文件,可以通过crawler_process.spider_loader.list() 实现。
如何获取所有的爬虫文件,如果要获取所有的爬虫文件,可以通过crawler_process.crawl(spname, **opts.spargs) 实现。

在这里,我们将新文件夹的命名为mycmd,在对应目录下创建该文件夹(位置在spiders目录的同级目录下),如下所示:

cd .mymultispd
mkdir mycmd
创建好文件夹再创建一个.py文件
复制下面代码

import os
from scrapy.commands import ScrapyCommand
from scrapy.utils.conf import arglist_to_dict
from scrapy.utils.python import without_none_values
from scrapy.exceptions import UsageError
 
 
class Command(ScrapyCommand):
 
    requires_project = True
 
    def syntax(self):
        return "[options] <spider>"
 
    def short_desc(self):
        return "Run a spider"
 
    def add_options(self, parser):
        ScrapyCommand.add_options(self, parser)
        parser.add_option("-a", dest="spargs", action="append", default=[], metavar="NAME=VALUE",
                          help="set spider argument (may be repeated)")
        parser.add_option("-o", "--output", metavar="FILE",
                          help="dump scraped items into FILE (use - for stdout)")
        parser.add_option("-t", "--output-format", metavar="FORMAT",
                          help="format to use for dumping items with -o")
 
    def process_options(self, args, opts):
        ScrapyCommand.process_options(self, args, opts)
        try:
            opts.spargs = arglist_to_dict(opts.spargs)
        except ValueError:
            raise UsageError("Invalid -a value, use -a NAME=VALUE", print_help=False)
        if opts.output:
            if opts.output == '-':
                self.settings.set('FEED_URI', 'stdout:', priority='cmdline')
            else:
                self.settings.set('FEED_URI', opts.output, priority='cmdline')
            feed_exporters = without_none_values(
                self.settings.getwithbase('FEED_EXPORTERS'))
            valid_output_formats = feed_exporters.keys()
            if not opts.output_format:
                opts.output_format = os.path.splitext(opts.output)[1].replace(".", "")
            if opts.output_format not in valid_output_formats:
                raise UsageError("Unrecognized output format '%s', set one"
                                 " using the '-t' switch or as a file extension"
                                 " from the supported list %s" % (opts.output_format,
                                                                  tuple(valid_output_formats)))
            self.settings.set('FEED_FORMAT', opts.output_format, priority='cmdline')
 
    def run(self, args, opts):
        if len(args) < 1:
            raise UsageError()
        elif len(args) > 1:
            raise UsageError("running 'scrapy crawl' with more than one spider is no longer supported")
        spname = args[0]
 
        self.crawler_process.crawl(spname, **opts.spargs)
        self.crawler_process.start()
再修改run
首先,将crawl命令的源码复制到该文件(mycrawl.py)中,然后进行修改:
 
    #主要修改这里
    def run(self, args, opts):
        #获取爬虫列表
        spd_loader_list=self.crawler_process.spider_loader.list()
        #遍历各爬虫
        for spname in spd_loader_list or args:
            self.crawler_process.crawl(spname, **opts.spargs)
            print("此时启动的爬虫为:"+spname)
        self.crawler_process.start()

然后,可以新建的该源代码文件的同级目录下添加一个初始化文件__init__.py,如下所示:
COMMANDS_MODULE = 'hell_scrapy.mycmd'
并添加进setting
COMMANDS_MODULE = 'hell_scrapy.mycmd'
随后,在命令行进入该项目所在的目录,并输入scrapy -h,出现如下所示的信息:
Available commands:
  bench         Run quick benchmark test
  check         Check spider contracts
  cmd           Run all spider
  crawl         Run a spider
  edit          Edit spider
  fetch         Fetch a URL using the Scrapy downloader
  genspider     Generate new spider using pre-defined templates
  list          List available spiders
  parse         Parse URL (using its spider) and print the results
  runspider     Run a self-contained spider (without creating a project)
  settings      Get settings values
  shell         Interactive scraping console
  startproject  Create new project
  version       Print Scrapy version
  view          Open URL in browser, as seen by Scrapy
发现有cmd 就是自己创建的.py文件,说明OK拉
再执行scrapy cmd --nolog
结果为

此时启动的爬虫为:myxmlspider
此时启动的爬虫为:weisuen
第1篇文章
标题是:
精通Python网络爬虫-新书介绍
对应的链接是:
[<Selector xpath='/html/head/title/text()' data='京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物!'>]
[<Selector xpath='/html/head/title/text()' data='新浪首页'>]


scrapy 避免被禁止


1.禁止cookie
有的网页会通过用户的cookie信息进行识别和分析,此时我们可以通过禁用本地cookie从而让对方网站无法识别
如何禁止呢
在对应的scrapy项目的setting 中
打开发现有这两行代码
# Disable cookies (enabled by default)
#COOKIES_ENABLED = False
只需要把
#COOKIES_ENABLED = False
注释取消就ok拉
# Disable cookies (enabled by default)
COOKIES_ENABLED = False
2.设置下载延时
有的网站通过访问的频率分析的
同样这样的设置在setting 里
# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
#DOWNLOAD_DELAY = 3
只需要把
DOWNLOAD_DELAY = 3
注释取消就Ok 拉,时间还可以自己设置
3就是三秒

3.使用ip代理池
如果同一个ip在短时间对服务器网页进行爬取,就会被禁止
所以 我们可以为scrapy项目建立一个下载中间件,在setting中配置好下载中间件并配置ip池
首先我们创建一个.py文件,由于我们需要大量的ip 所以可以在
http://yum.iqianyue.com/proxy里去找

找到这些ip后,我们在setting里面添加如下
#ip池设置
IPPOOL=[
    {'ipaddr':'121.33.24.2...'},
    {'ipaddr':'121.33.24.2...'},
    {'ipaddr':'121.33.24.2...'},
    {'ipaddr':'121.33.24.2...'},
    {'ipaddr':'121.33.24.2...'},
]
此时,IPPOOL就是对应的代理服务器的ip池
设置好ip池后,我们需要编写下载中间件文件,也就是我们先前创建的.py文件
在scrapy中,与代理服务器设置相关的下载中间件事HttpProxyMiddleware
所以详细 参看官方文档
import random
from hell_scrapy.setting import IPPOOL
from scrapy.contrb.downloadermiddleware.httpproxy import HttpProxyMiddleware

class IPPOOLS(HttpProxyMiddleware):
    def __init__(self,ip=''):
        self.ip=ip
    def process_request(self,request,spider):
        this_ip=random.choice(IPPOOL)
        print('当前选择的ip是:'+this_ip['ipaddr])
        request.meta['proxy']='http://'+this_ip['ipaddr']
编写好后,由于这只是一个普通middle.py文件,所以我们需要在setting中配置下
#DOWNLOADER_MIDDLEWARES = {
#    'hell_scrapy.middlewares.HellScrapyDownloaderMiddleware': 543,
#}
更改为
DOWNLOADER_MIDDLEWARES = {
#    'hell_scrapy.middlewares.HellScrapyDownloaderMiddleware': 543,
'scrapy.contrb.downloadermiddleware.httpproxy.HttpProxyMiddleware':123 #根据官方文档配置这个
'hell_scrapy.middle.IPPOOLS':125
}
配置好了后运行scrapy crawl weisuen --nolog  ok 拉


scrapy实战

创建项目scrapy startproject name

item编写
这里是我们想要的信息
class AutopjtItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name=scrapy.Field()
    price=scrapy.Field()
    link=scrapy.Field()
    comnum=scrapy.Field()
pipeline编写
这里是存蓄
import json
import codecs

class AutopjtPipeline(object):
    def __init__(self):
        self.file=codes.open('D:Python_codescrapy_envautopjtmydata','wb',encoding='utf-8')
    def process_item(self, item, spider): #听名字就知道这是处理item的函数,当然返回的也是处理后的item
        i=json.dumps(dict(item),ensure_ascii=False)
        line=i+'
'
        self.file.write(line)
        return item
    def close_spider(self,spider):
        self.file.close()
srtting 编写
打开item_pipelines
打开cookie
将robotstxt设置fasle

这时出现一点小错误,没有库
解决是打开setting找到虚拟环境,用已存在的虚拟scrapy_env就OK拉

自动爬虫的编写
scrapy genspider -t basic autospd dangdang.com 依据的模板是basic不是xmlfeed等其他
import scrapy
from autopjt.items import AutopjtItem
from scrapy.http import Request
class AutospdSpider(scrapy.Spider):
    name = 'autospd'
    allowed_domains = ['dangdang.com']
    start_urls = ['http://search.dangdang.com/?key=%BB%A8%C9%FA%D3%CD&act=input&page_index=1']

    def parse(self, response):
        item=AutopjtItem()
        #
        item['name']=response.xpath("//a[@class='pic']/@title").extract()
        item['price']=response.xpath("//span[@class='price_n']/text()").extract()
        item['link']=response.xpath("//a[@class='pic']/@href").extract()
        item['comnum']=response.xpath("//a[@name='P_p1']/text()").extract()
        yield item
        for i in range(1.5):
            url='http://search.dangdang.com/?key=%BB%A8%C9%FA%D3%CD&act=input&page_index='+str(i)
            yield Request(url,callback=self.parse)

这是源码
<a title=" 美临 小榨花生油 5L 浓香花生油" ddclick="act=normalResult_picture&amp;pos=1352623776_0_1_q" class="pic" name="itemlist-picture" dd_name="单品图片" href="http://product.dangdang.com/1352623776.html" target="_blank"><img src="http://img3m6.ddimg.cn/42/13/1352623776-1_b_1.jpg" alt=" 美临 小榨花生油 5L 浓香花生油"><p class="cool_label"></p></a>
<p class="price"> <span class="price_n">¥128.00</span></p>
<p class="name" name="title"><a title=" 美临 小榨花生油 5L 浓香花生油" href="http://product.dangdang.com/1352623776.html" name="itemlist-title" dd_name="单品标题" ddclick="act=normalResult_title&amp;pos=1352623776_0_1_q" target="_blank"> 美临 小榨<font class="skcolor_ljg">花生油</font> 5L 浓香<font class="skcolor_ljg">花生油</font></a></p>
<p class="link"><a href="http://shop.dangdang.com/21079" name="itemlist-shop-name" dd_name="单品店铺" target="_blank" title="美临旗舰店">美临旗舰店</a></p>
<p class="star"><span class="level"><span style=" 100%;"></span></span><a href="http://product.dangdang.com/1352623776.html?point=comment_point" target="_blank" name="itemlist-review" dd_name="单品评论" ddclick="act=click_review_count&amp;pos=1352623776_0_1_q">333条评论</a></p>

crawlspider

item
    name=scrapy.Field()
    link=scrapy.Field()
pipeline
class CrawlPipeline(object):
    def process_item(self, item, spider):
        print(item['name'])
        print(item['link'])
        print('--------------')
        return item

scrapy genspider -l查看
有crawlspider
然后scrapy gendpider -t crawl name sohu.com

from crawl.items import CrawlItem

class CrawlspiderSpider(CrawlSpider):
    name = 'crawlspider'
    allowed_domains = ['sohu.com']
    start_urls = ['http://www.sohu.com/']

    # rules = (
    #     Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    # )
    rules = (
        Rule(LinkExtractor(allow=('.*?/n.*?shtml'), allowed_domains=('sohu.com')), follow=True),
    )
    def parse_item(self, response):
        i=CrawlItem()
        i['name']=response.xpath("/html/head/title/text()").extract()
        i['link']=response.xpath("//link[@rel='canonical']/@href").extract()
        #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
        #item['name'] = response.xpath('//div[@id="name"]').get()
        #item['description'] = response.xpath('//div[@id="description"]').get()
        return i

原文地址:https://www.cnblogs.com/yangj-Blog/p/13123636.html