爬虫基础知识+Scrapy框架

URI和URL的概念

URI通用资源标志符

  • 访问资源的命名机制

  • 存放资源的主机名

  • 资源自身 的名称,由路径表示

http://www.why.com.cn/myhtml/html1223/
①这是一个可以通过HTTP协议访问的资源
②位于主机 www.webmonkey.com.cn上
③通过路径“/html/html40”访问

URL统一资源定位符

  • URI的子集

  • 在这里插入图片描述

requests

步骤:

1.指定URL

2.进行URL伪装

3.请求参数处理

  • 创建字典 字典内放参数

4.发送请求

  • get请求 response=request.get(url=,param=,headers=)
  • post请求 response=request.post(url=,data=,headers=)

5.获取响应数据

  • response.text
  • response.json
  • 具体情况根据页面信息决定

6.持久化存储

  • 存到文件里
  • 在这里插入图片描述

7.数据解析

在这里插入图片描述

①正则解析

  • text返回字符串形式数据
  • content返回二进制形式图片数据
  • json返回对象类型图片数据
<div class="thumb">

<a href="/article/121721100" target="_blank">
<img src="//pic.qiushibaike.com/system/pictures/12172/121721100/medium/DNXDX9TZ8SDU6OK2.jpg" alt="指引我有前进的方向">
</a>
</div>
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'

② bs4解析

  • 数据解析的原理:
    1.标签定位
    2.提取标签、标签属性中存储的数据值

  • bs4数据解析的原理:

    • 实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
    • 通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取
  • 如何实例化BeautifulSoup对象:

    • from bs4 import BeautifulSoup
    • 对象的实例化:
      • 将本地的html文档中的数据加载到该对象中

                 fp = open('./test.html','r',encoding='utf-8')
                 soup = BeautifulSoup(fp,'lxml')
        
      • 将互联网上获取的页面源码加载到该对象中

                 page_text = response.text
                 soup = BeatifulSoup(page_text,'lxml')
        
    • 提供的用于数据解析的方法和属性:
      • soup.tagName:返回的是文档中第一次出现的tagName对应的标签
      • soup.find():
        • find(‘tagName’):等同于soup.div
        • 属性定位:
          • soup.find(‘div’,class_/id/attr=‘song’)
      • soup.find_all(‘tagName’):返回符合要求的所有标签(列表)
    • select:
      • select(‘某种选择器(id,class,标签…选择器)’),返回的是一个列表。
      • 层级选择器:
        • soup.select(‘.tang > ul > li > a’):>表示的是一个层级
        • oup.select(‘.tang > ul a’):空格表示的多个层级
    • 获取标签之间的文本数据:
      • soup.a.text/string/get_text()
      • text/get_text():可以获取某一个标签中所有的文本内容
      • string:只可以获取该标签下面直系的文本内容
    • 获取标签中属性值:
      • soup.a[‘href’]

③XPath

  • xpath表达式:
    • /:表示的是从根节点开始定位。表示的是一个层级。
    • //:表示的是多个层级。可以表示从任意位置开始定位。
    • 属性定位://div[@class=‘song’] tag[@attrName=“attrValue”]
    • 索引定位://div[@class=“song”]/p[3] 索引是从1开始的。
    • 取文本:
      • /text() 获取的是标签中直系的文本内容
      • //text() 标签中非直系的文本内容(所有的文本内容)
    • 取属性:
      • /@attrName ==>img/src

模拟登陆(验证码)超级鹰

①先获取登陆界面的网络源码
②用xpath解析网络源码获取验证码图片的src
③获取验证码图片并下载到本地
④用超级鹰识别验证码图片
(在正式模拟登陆时 先正确登陆一次获取post请求的data将它们以字典形式存在 复制post请求的URL)
⑤模拟登陆 URL=‘post请求里的URL’ request.get(url=url,headers=header,data=data) 发送post请求
⑥运行

import requests
from hashlib import md5
from lxml import etree
from chaojiying import Chaojiying_Client


# 获取网络源码
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
url='https://www.chaojiying.com/user/login/'
page_text=requests.get(url=url,headers=headers).text

# 实例化一个etree对象
tree=etree.HTML(page_text)
img_src='https://www.chaojiying.com/'+tree.xpath('/html/body/div[3]/div/div[3]/div[1]/form/div/img/@src')[0]

# 下载验证码图片到本地
img_data=requests.get(url=img_src,headers=headers).content
with open('./code.jpg','wb') as fp:
    fp.write(img_data)

# 用超级鹰识别
chaojiying=Chaojiying_Client('jshn9774','luozhi74803','938388')
im = open('./code.jpg', 'rb').read()							
print(chaojiying.PostPic(im, 1902))
img_text = chaojiying.PostPic(im, 1902)['pic_str']
# 模拟登陆
data={
    'user': '超级鹰账号',
    'pass': '超级鹰密码',
    'imgtxt': img_text,
    'act': '1',
}
# 这里的URL是post请求里的URL network->data
url_login='https://www.chaojiying.com/user/login/'
# 模拟登陆的post请求
data_p=requests.post(url=url,headers=headers,data=data).text
print(data_p)

Cookies

  • http/https协议特性:无状态。
  • 没有请求到对应页面数据的原因:
    • 发起的第二次基于个人主页页面请求的时候,服务器端并不知道该此请求是基于登录状态下的请求。
  • cookie:用来让服务器端记录客户端的相关状态。
    • 手动处理:通过抓包工具获取cookie值,将该值封装到headers中。(不建议)
    • 自动处理:
      • cookie值的来源是哪里?
        • 模拟登录post请求后,由服务器端创建。
      • session会话对象:
        • 作用:
          1.可以进行请求的发送。
          2.如果请求过程中产生了cookie,则该cookie会被自动存储/携带在该session对象中。
      • 创建一个session对象:session = requests.Session()
      • 使用session对象进行模拟登录post请求的发送(cookie就会被存储在session中)
      • session对象对个人主页对应的get请求进行发送(携带了cookie)

代理

  • 什么是代理:

    • 代理服务器。
  • 代理的作用:

    • 突破自身IP访问的限制。
    • 隐藏自身真实IP
  • 代理ip的类型:

    • http:应用到http协议对应的url中
    • https:应用到https协议对应的url中
  • 代理ip的匿名度:

    • 透明:服务器知道该次请求使用了代理,也知道请求对应的真实ip
    • 匿名:知道使用了代理,不知道真实ip
    • 高匿:不知道使用了代理,更不知道真实的ip

异步爬虫

协程

  • 在一个线程中如果遇到IO等待时间,线程不会傻傻等,而是利用空闲时间去执行别的任务
  1. 事件循环

  2. 快速上手

  3. await

    • await +可等待对象 (协程对象、Future、Task对象->IO等待)
    • await 等待对象的值得到结果后再继续往下走
    • 下一步要依赖上一步的结构是要用到await 在一条总线上等待 但依旧会切到别的地方执行别的任务
  4. Task对象

    • 在事件循环中添加多个任务
     import asyncio
     async def func():
     	print(1)
     await asyncio.sleep(2)
     	print(2)
     	return "返回值"
     async def main():
     	print("main开始")
    
     # 创建Task对象,将当前执行func函数任务添加到事件循环
     # task1=asyncio.create_task(func())
     #
     # # 创建Task对象,将当前执行func函数任务添加到事件循环
     # task2 = asyncio.create_task(func())
         task_list=[
         	asyncio.create_task(func()),
         	asyncio.create_task(func()),
     ]
     	print("main结束")
     	done,pending=await asyncio.wait(task_list,timeout=None)
     	print(done)
     asyncio.run(main()) 
    
    

selenium

  • selenium是基于浏览器自动化的一个模块
  • 编写基于浏览器自动化的操作代码
    • 发起请求:get(url)
    • 标签定位:find系列的方法
    • 标签交互:send_keys(‘xxx’)
    • 执行js程序:excute_script(‘jsCode’)
    • 前进,后退:back(),forward()
    • 关闭浏览器:quit()

selenium模块和爬虫之间具有怎样的关联?

  • 便捷的获取网站中动态加载的数据
  • 便捷实现模拟登录

selenium处理iframe

- 如果定位的标签存在于iframe标签之中,则必须使用switch_to.frame(id)
- 动作链(拖动):from selenium.webdriver import ActionChains
    - 实例化一个动作链对象:action = ActionChains(bro)
    - click_and_hold(div):长按且点击操作
    - move_by_offset(x,y)
    - perform()让动作链立即执行
    - action.release()释放动作链对象

无头浏览器

# 实现无可视化界面
from selenium.webdriver.chrome.options import Options
# 实现无可视化界面的操作
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

规避检测

# 实现规避检测
from selenium.webdriver import ChromeOptions
# 实现规避检测
option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])

Scrapy框架

  • 框架是一个集成了很多功能并且具有很强通用性的一个项目模板

  • scrapy使用步骤

    • 创建一个工程:scrapy startproject 工程名
    • cd 工程文件夹
    • 在spiders子目录中创建一个爬虫文件 :
      scrapy genspider 文件名 www.xxx.com
    • 执行工程:
      scrapy crawl spiderName(爬虫文件名称)
import scrapy


class FirstSpider(scrapy.Spider):
    # 爬虫文件的名称:就是爬虫源文件的一个唯一标识
    name = 'first'
    # 允许的域名:用来限定start_urls列表中哪些url可以进行请求发送
    allowed_domains = ['www.baidu.com']
    # 起始的url列表:该列表中存放的url会被scrapy自动进行请求的发送
    start_urls = ['https://www.baidu.com/','https://www.sogou.com']

    # 用作数据解析:response参数表示请求成功后对应的响应对象
    def parse(self, response):
        print(response)

Scrapy持久化存储

  1. 基于终端指令:

    • 只可以将parse方法的返回值存储到本地的文本文件中

    • 存储类型是’json’, ‘jsonlines’, ‘jl’, ‘csv’, ‘xml’, ‘marshal’, ‘pickle’

    • 终端指令:scrapy crawl 项目名称 -o filePath
      
    • 好处:简介高效便捷

    • 缺点:局限性比较强(数据只可以存储到指定后缀的文本文件中)

  2. 基于管道:

    • 数据解析

    • 在item类中定义相关的属性

    • 将解析的数据封装存储到item类型的对象

    • 将item类型的对象提交给管道进行持久化存储的操作

    • 在管道类的process_item中要将其接受到的item对象中存储的数据进行持久化存储操作

    • 在配置文件中开启管道

    • 好处:通用性强

    • 管道文件中一个管道类对应将一组数据存储到一个平台或载体中

    class LiepinPipeline:
     fp=None
     # 该方法开始爬虫的时候调用一次
     def open_spider(self,spider):
         print("爬虫开始")
         self.fp=open('./liepin.txt','w',encoding='utf-8')
    
     def process_item(self, item, spider):
         title=item['title']
         area=item['area']
         money=item['money']
         require=item['require']
         name=item['name']
         self.fp.write(title+area+money+require+name+'\n')
    
         return item
     # 只在结束时打开一次
     def close_spider(self,spider):
         print("结束爬虫")
         self.fp.close()
         ```
    

面试题:将爬取到的数据一份存储到本地一份存储到数据库,如何实现?

  • 管道文件中一个管道类对应的是将数据存储到一种平台
  • 爬虫文件提交的item只会给管道文件中第一个被执行的管道类接受
  • process_item中的return item表示将item传递给下一个即将被执行的管道类

基于Spider的全站数据爬取

  • 就是将网站中某板块下的全部页码对应的页面数据进行爬取
  • 实现方式:
    • 将所有页面的url添加到start_urls列表(不推荐)
    • 自行手动进行请求发送(推荐)
      • 手动请求发送:
        • yield scrapy.Request(url,callback):callback专门用做于数据解析

五大核心

  • 引擎(Scrapy)
    用来处理整个系统的数据流处理, 触发事务(框架核心)

  • 调度器(Scheduler)
    用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址

  • 下载器(Downloader)
    用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)

  • 爬虫(Spiders)
    爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面

  • 项目管道(Pipeline)
    负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。

在这里插入图片描述

请求传参

  • 使用场景:要爬取解析的数据不再同一张页面中(深度爬取)
  • 请求传参传的是item的对象类型 (通过请求 把参数传到对应的函数)
  • 因为需要将不同页面的数据解析存储到同一个item里
           # 发送获取详情页的请求
           # 手动请求的发送
           # 请求传参 meta={} ,可以将meta字典传递给请求对应的回调函数
           # yield scrapy.Resqult(detail_url,callback=self.parse_detail,meta={'item':item})

用scrapy进行图片爬取 ImagesPipeline

基础scrapy爬取字符串类型的数据和爬取图片类型的数据的区别

  • 字符串:只需要基于xpath进行解析且提交管道进行持久化存储
  • 图片:xpath解析出图片输入层的属性值 单独的对图片发起请求获取图片二进制类型的数据
  • ImagesPipeline:只需要将图片的src属性值进行解析,提交到管道,管道就会对图片的src进行请求发送请求获取图片的二进制类型的数据,且还会帮我们进行持久化存储。
    • 数据解析(图片的地址)
    • 将存储图片地址的item提交到指定的管道类
    • 在管道文件中自定制一个基于ImagesPipeLine的一个管道类
      • get_media_request
      • file_path
      • item_completed
    • 在配置文件中:
      • 指定图片存储的目录:IMAGES_STORE = ‘./imgs_bobo’
      • 指定开启的管道:自定制的管道类

爬取百度图片

  • 百度图片是以json形式保存的
imgs=json.loads(response.body)['data']

        for img in imgs:
            item=JsonproItem()
            try:
                item['url']=[img['middleURL']]
                yield item
            except Exception as e:
                print(e)

中间件

  • 下载中间件

    • 引擎和下载器之间
    • 作用:批量拦截到整个工程中所有的请求和响应
    • 拦截请求:
      • UA伪装 process_request
      • 代理ip process_exception :return request
    • 拦截响应
      • 篡改响应数据、响应对象
class MiddleDownloaderMiddleware:
	user_agent_list = [
        'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0'
        ,
        'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
        'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11'
        , 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)',
        'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)'
        , 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)',
        'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)',
        'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)']
# ip代理池需要自己建(要钱)
# 列表内容为   ip地址:端口号   
# 例子如下
PROXY_https=[]
PROXY_http=['120.194.55.139:6969','111.3.118.247:30001']
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s
   
# 拦截请求
    def process_request(self, request, spider):    
    	 # 为了验证代理的操作是否生效
        request.meta['proxy']='http://116.62.198.43:8080'

        # UA伪装
        request.header['User-Agent']=random.choice(self.user_agent_list)
        request.meta['proxy']='http://122.9.101.6:8888'
        return request
    # 拦截所有响应
    def process_response(self, request, response, spider):
        return response
    
     # 拦截发生异常的请求
    def process_exception(self, request, exception, spider):
         if request.url.split(':')[0]=='http':
             # 代理							request.meta['proxy']='http://'+random.choice(self.PROXY_http)
        else:  			request.meta['proxy']='https://'+random.choice(self.PROXY_https)

        # 将修正后的请求对象进行重新的请求发送
        return  request
     def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)

JSON常识

  1. (JavaScript Object Notation ) JavaScript对象表示法是一种轻量级(Light-Meight)、基于文本的(Text-Based)、可读的(Human-Readable)格式

  2. JSON 的名称中虽然带有JavaScript,但这是指其语法规则是参考JavaScript对象的,而不是指只能用于JavaScript 语言。

  3. 相比 XML(另一种常见的数据交换格式),文件更小

  4. 语法规则:

    • 数组(Array)用方括号(“[]”)表示

    • 对象(0bject)用大括号(“{}”)表示

    • 名称/值对(name/value)组合成数组和对象。

    • 名称(name)置于双引号中,值(value)有字符串、数值、布尔值、null、对象和数组

    • 并列的数据之间用逗号(“,”)分隔

    JSON和XML

    • JSON的优势

      • 没有结束标签、长度更短、读写更快

      • 能够直接被JavaScript解释器解析

      • 可以使用数组

# JSON
{
	"name":"兮动人",
	"age":22,
	"fruits":["apple","pear","grape"]
}

# XML
<root>
	<name>兮动人</name>
	<age>22</age>
	<fruits>apple</fruits>
	<fruits>pear</fruits>
	<fruits>grape</fruits>
</root>
  1. 格式规定
  • 对象(0bject)
    • 对象用大括号(“{}”)括起来,大括号里是一系列的“名称/值对
    • 两个并列的数据之间用逗号(“,”)隔开
      • 使用英文的逗号(“,”),不要用中文的逗号(“”)
      • 最后一个“名称/值对“之后不要加逗号
  • 数组(Array)
    • 数组表示一系列有序的值,用方括号(“[]”)包围起来,并列的值之间用逗号分隔
  • 名称/值对(Name/Value)
    • 名称(Name)是一个字符串,要用双引号括起来,不能用单引号也不能没有引号,这一点与JavaScript不同
    • 值的类型只有七种:字符串(string)、数值(number)、对象(object)、数组(array), true、false、null不能有这之外的类型,例如undefined、函数等。
    • 字符串中不能单独出现双引号()和右斜杠(“\")
    • 如果要打双引号或右斜杠,需要使用“右斜杠+字符”的形式,例如\”\\,其它的转义字符也是如此

CrawlSpider:类 Spider的一个子类

全站数据爬取的方式:

  • 基于Spider:手动请求,然后构造通用url模板

  • 基于CrawlSpider

    • CrawlSpider的使用:

      • - 创建一个工程
        - cd XXX
        - 创建爬虫文件(CrawlSpider)
        	- scrapy genspider -t crawl xxx www.xxx.com
        	- 链接提取器 
        		- 根据指定规则(allow 具体参数是正则表达式)进行指定链接的提取
        	- 规则提取器
        		- 将链接提取器提取到的链接进行指定规则(callback)的解析操作
        
        
"spider.py"
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from sunPro.items import SunproItem,DetailItem

#需求:爬取sun网站中的编号,新闻标题,新闻内容,标号
class SunSpider(CrawlSpider):
    name = 'sun'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=']

    #链接提取器:根据指定规则(allow="正则")进行指定链接的提取
    link = LinkExtractor(allow=r'type=4&page=\d+')
    link_detail = LinkExtractor(allow=r'question/\d+/\d+\.shtml')
    rules = (
        #规则解析器:将链接提取器提取到的链接进行指定规则(callback)的解析操作
        Rule(link, callback='parse_item', follow=True),
        #follow=True:可以将链接提取器 继续作用到 连接提取器提取到的链接 所对应的页面中
        Rule(link_detail,callback='parse_detail')
    )
    #http://wz.sun0769.com/html/question/201907/421001.shtml
    #http://wz.sun0769.com/html/question/201907/420987.shtml

    #解析新闻编号和新闻的标题
    #如下两个解析方法中是不可以实现请求传参!
    #如法将两个解析方法解析的数据存储到同一个item中,可以以此存储到两个item
    def parse_item(self, response):
        #注意:xpath表达式中不可以出现tbody标签
        tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')
        for tr in tr_list:
            new_num = tr.xpath('./td[1]/text()').extract_first()
            new_title = tr.xpath('./td[2]/a[2]/@title').extract_first()
            item = SunproItem()
            item['title'] = new_title
            item['new_num'] = new_num

            yield item

    #解析新闻内容和新闻编号
    def parse_detail(self,response):
        new_id = response.xpath('/html/body/div[9]/table[1]//tr/td[2]/span[2]/text()').extract_first()
        new_content = response.xpath('/html/body/div[9]/table[2]//tr[1]//text()').extract()
        new_content = ''.join(new_content)

        # print(new_id,new_content)
        item = DetailItem()
        item['content'] = new_content
        item['new_id'] = new_id

        yield item

分布式爬虫

  • 概念:需要搭建一个分布式的机群,让其对一组资源进行分布联合爬取

  • 作用:提升爬取数据的效率

  • 为什么scrapy不嗯呢该实现分布式?

    • 调度器不可以被分布式机群共享
    • 管道不能被嗯不是机群共享
  • scrapy-Redis组件的作用:

    • 可以给原生的的scrapy框架提供可以被共享的管道和调度器

    • - 实现流程
          - 创建一个工程
          - 创建一个基于CrawlSpider的爬虫文件
          - 修改当前的爬虫文件:
              - 导包:from scrapy_redis.spiders import RedisCrawlSpider
              - 将start_urls和allowed_domains进行注释
              - 添加一个新属性:redis_key = 'sun' 可以被共享的调度器队列的名称
              - 编写数据解析相关的操作
              - 将当前爬虫类的父类修改成RedisCrawlSpider
          - 修改配置文件settings
              - 指定使用可以被共享的管道:
                  ITEM_PIPELINES = {
                      'scrapy_redis.pipelines.RedisPipeline': 400
                  }
              - 指定调度器:
                  # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化
                  DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
                  # 使用scrapy-redis组件自己的调度器
                  SCHEDULER = "scrapy_redis.scheduler.Scheduler"
                  # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据
                  SCHEDULER_PERSIST = True
              - 指定redis服务器:
          - redis相关操作配置:
                      - 配置redis的配置文件:
                          - linux或者mac:redis.conf
                          - windows:redis.windows.conf
                          - 代开配置文件修改:
                              - 将bind 127.0.0.1进行删除
                              - 关闭保护模式:protected-mode yes改为no
                      - 结合着配置文件开启redis服务
                          - redis-server 配置文件
                      - 启动客户端:
                          - redis-cli
                  - 执行工程:
                      - scrapy runspider xxx.py
                  - 向调度器的队列中放入一个起始的url:
                      - 调度器的队列在redis的客户端中
                          - lpush xxx www.xxx.com
                  - 爬取到的数据存储在了redis的proName:items这个数据结构中
      
      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值