全国旗舰校区

不同学习城市 同样授课品质

北京

深圳

上海

广州

郑州

大连

武汉

成都

西安

杭州

青岛

重庆

长沙

哈尔滨

南京

太原

沈阳

合肥

贵阳

济南

下一个校区
就在你家门口
+
当前位置:首页  >  技术干货

20天学会数据分析之Scrapy框架搭建Cookies池和IP代理池附案例

发布时间:2022-09-20 16:24:35
发布人:qyf

  Cookies介绍

  在浏览网站的过程中,我们经常会遇到需要登录的情况,有些页面只有登录之后才可以访问,而且登录之后可以连续访问很多次网站,但是有时候过一段时间就需要重新登录。还有一些网站,在打开浏览器时就自动登录了,而且很长时间都不会失效,这种情况又是为什么?其实这里面涉及Session和Cookies的相关知识,先来揭开Cookies的面纱。

  要介绍Cookies我们必须要知道为什么需要Cookies?源于HTTP协议的无状态。

  HTTP的无状态是指HTTP协议对事务处理是没有记忆能力的,也就是说服务器不知道客户端是什么状态。当我们向服务器发送请求后,服务器解析此请求,然后返回对应的响应,服务器负责完成这个过程,而且这个过程是完全独立的,服务器不会记录前后状态的变化,也就是缺少状态记录。

  为了保持前后状态,我们肯定不能将前面的请求全部重传一次,这太浪费资源了,对于这种需要用户登录的页面来说,更是棘手。这时两个用于保持HTTP连接状态的技术就出现了,它们分别是Session和Cookies。

  Cookies是在客户端,也可以理解为浏览器端,有了Cookies,浏览器在下次访问网页时会自动附带上它发送给服务器,服务器通过识别Cookies并鉴定出是哪个用户,然后再判断用户是否是登录状态,然后返回对应的响应。也可以理解为Cookies里面保存了登录的凭证,有了它,只需要在下次请求携带Cookies发送请求而不必重新输入用户名、密码等信息重新登录了。

  因此在爬虫中,有时候处理需要登录才能访问的页面时,我们一般会直接将登录成功后获取的Cookies放在请求头里面直接请求,而不必重新模拟登录。

  Cookies的属性结构

  以爬取相亲网站珍爱网为例,打开首页查看存储在本地的Cookies。

  Chrome浏览器中的Cookie截图,属性分别有Name、Value、Domain、Path、Expires/Max-age、Size、HttpOnly、Secure、SameSite和Priority组成。

  Name和Value是一个键值对。Name是Cookie的名称,Cookie一旦创建,名称便不可更改。Value是该名称对应的Cookie的值,如果值为Unicode字符,需要为字符编码。

  Domain决定Cookie在哪个域是有效的。例如,如果设置为.zhenai.com,则所有以zhenai.com,结尾的域名都可以访问该Cookie。

  Path该Cookie的使用路径。如果设置为/path/,则只有路径为/path/的页面可以访问该Cookie。如果设置为/,则本域名下的所有页面都可以访问该Cookie。

  Expires和Max-age均为Cookie的有效期,Expires是该Cookie被删除时的时间戳,格式为GMT。Max-age也是Cookie的有效期,但它的单位为秒,即多少秒之后失效。若Max-age设置为0,则立刻失效,设置为负数,则在页面关闭时失效。Max-age默认为 -1。

  Size是此Cookie的大小。在所有浏览器中,任何cookie大小超过限制都被忽略,且永远不会被设置。

  HttpOnly值为 true 或 false,若设置为true,则不允许通过脚本document.cookie去更改这个值,同样这个值在document.cookie中也不可见,但在发送请求时依旧会携带此Cookie。

  Secure为Cookie的安全属性,若设置为true,则浏览器只会在HTTPS和SSL等安全协议中传输此Cookie,不会在不安全的HTTP协议中传输此Cookie。

  SameSite用来限制第三方 Cookie,从而减少安全风险。它有3个属性,分别是:1.Strict 严格 2.Lax 稍微放宽 3.None

  Cookies以键值的方式记录会话跟踪的内容.服务器利用响应报头Set-Cookie来发送COOKIE信息.在RFC2109中定义的SET-COOKIE响应报头的格式为:

  Set-Cookie: Name = Value; Comment = value; Domain = value; Max-Age = value; Path = Value;Secure; Version = 1 * DIGIT;

  Cookies池介绍

  平时我们在对网站进行数据抓取的时候,可以抓取一部分页面或者接口(因为毕竟网站本身须要做SEO,不会对所有网站页面都设置登陆限制),这部分可能没有设置登录限制。但是如果要抓取大规模数据的时候,没有登录进行爬取会出现一些问题。

  设置了登陆限制的网站页面无法抓取。

  对于一些没有设置登录的页面或者接口,一旦IP访问频繁,会触发网站的反爬虫

  所以我们可以构建一个Cookies池,存储用户名和cookie的映射。Cookies池中保存了许多新浪微博账号和登陆后的Cookies信息,并且Cookies池还须要定时检测每个Cookies的有效性,如果某Cookies无效,那就删除该Cookies并模拟登陆生成新的Cookies。同时Cookies池还须要一个非常重要的接口,即获取随机Cookies的接口,Cookies运行后,咱们只需请求该接口,即可随机获得一个Cookies并用其抓取。

  思路

  首先我们需要多个可以登录的Cookies,然后利用这些Cookies去下载网页;一旦返回状态码不是200,就拉黑该Cookies。

  具体的方法看下图:

  可以使用Flask做一个API接口,每请求一次返回一个json,json中含有对应账号的Cookies。

  下载CookiesPool代码GitHub:https://github.com/Python3WebSpider/CookiesPool

  链接中给出的weibo的账号和密码,但是现在weibo的账号和密码登录之后需要手机验证码,需要提升此功能。或者进行其他网站的爬取也可以。

  Scrapy中使用Cookies池

  在项目settings.py中添加:

  COOKIES_URL = 'http://127.0.0.1:5000/xxx/random'

  上面提到的CookiesPool是一个基于Flask的项目,所以需要按照GitHub中的说明,进行部署启动服务器。每次发出请求获取一次Cookies。

  Scrapy-Redis的配置

  核心配置

  首先最主要的是,需要将调度器的类和去重的类替换为 Scrapy-Redis 提供的类,在 settings.py 里面添加如下配置即可:

  SCHEDULER = "scrapy_redis.scheduler.Scheduler"

  DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

  Redis 连接配置

  接下来配置 Redis 的连接信息,我们可以用 Redis 的地址、端口、密码来构造一个 Redis 连接字符串,支持的连接形式如下所示:

  redis://[:password]@host:port/db

  password 是密码,比如要以冒号开头,中括号代表此选项可有可无,host 是 Redis 的地址,port 是运行端口,db 是数据库代号,其值默认是 0。 根据上文中提到我的 Redis 连接信息,构造这个 Redis 的连接字符串如下所示:

  redis://:foobared@127.0.0.1:6379

  如果没有密码则使用下面的

  redis://@127.0.0.1:6379

  直接在 settings.py 里面配置为 REDIS_URL 变量即可:

  REDIS_URL = 'redis://:foobared@127.0.0.1:6379'

  也可以分项单独配置。这个配置就更加直观明了,如根据我的 Redis 连接信息,可以在 settings.py 中配置如下代码:

  REDIS_HOST = '127.0.0.1'

  REDIS_PORT = 6379

  REDIS_PASSWORD = 'foobared' # 没有password可以省略

  配置调度队列

  此项配置是可选的,默认使用 PriorityQueue。如果想要更改配置,可以配置 SCHEDULERQUEUECLASS 变量

  scrapy_redis.queue.FifoQueue 先进先出

  scrapy_redis.queue.LifoQueue 后进先出

  scrapy_redis.queue.PriorityQueue (默认的)

  SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'

  还可以配置持久化,SCHEDULERPERSIST用来将Requests队列持久化到Redis,可支持暂停或重启爬虫。将 SCHEDULERPERSIST 设置为 True 之后,爬取队列和去重指纹集合不会在爬取完成后自动清空,如果不配置,默认是 False,即自动清空。

  SCHEDULER_PERSIST = True

  另外如果需要配置中断重爬,需要添加如下代码(这样将 SCHEDULERFLUSHON_START 设置为 True 之后,爬虫每次启动时,爬取队列和指纹集合都会清空。)

  SCHEDULER_FLUSH_ON_START = True

  还有一个最重要的就是配置存储目标数据库。我们采用MongoDB。配置如下

  MONGO_URI = 'mongodb://用户名:密码@127.0.0.1:27017' # 如果没有用户名和密码可以省略

  代理IP

  代理IP到底是干什么的呢?其实代理IP可以说是一个中转站,就是你在访问互联网的时候,现在你的设备上连接IP代理,然后通过这个IP代理中转站提供的IP地址来上网。代理IP的作用也不难理解,就是用这样中转的方式来隐藏真实IP,转发请求,客户端向代理服务器发送请求,代理服务器请求到目标服务器,这样一来目标服务器收到请求后,记录的就是代理服务器的IP地址而不是真实的IP地址。整个过程下来,与目标服务器连接的都是代理服务器而非真实的客户端,从而达到了隐藏真实IP的目的。

  而代理IP应用的场景也很多,例如:使用代理IP用于网络投票,使用代理IP来挖掘数据,使用代理IP进行品牌监控,舆情监控,人工智能,网络营销等等场景。

  为什么需要代理

  • 突破自身IP访问限制,访问一些平时不能访问的站点。

  • 访问一些单位或团体内部资源:比如使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。

  • 提高访问速度:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时,则直接由缓冲区中取出信息,传给用户,以提高访问速度。

  • 隐藏真实IP:上网者也可以通过这种方法隐藏自己的IP,免受攻击。对于爬虫来说,我们用代理就是为了隐藏自身IP,防止自身的IP被封锁。

  对于我们爬虫来说,使用代理也是因为网站的反爬策略。因为现在很多网站都会有反爬虫措施,爬虫在采集过程中会发出大量的请求,使用同一个IP地址很容易触发网站的反爬虫措施,因此IP就会被限制,导致采集工作无法继续。如果想让爬虫继续下去,就需要更换IP地址,爬虫换了新的IP之后就可以继续工作了。

  IP代理池

  对于封IP的网站。需要很多的代理IP,去买代理IP,而对于初学者觉得没有必要,每个卖代理IP的网站有的提供了免费IP,可是又很少,写了个IP代理池 。仍然是写了一个爬虫代理,可以通过运行此代码获得更多的免费IP。

  代码比较多可以回复:IP代理池获取 (注意要关注此可以哦! )

  Scrapy中使用IP代理池

  如果在Scrapy中使用代理池需要提起做好配置

  首先启动IP代理池,添加Scrapy的中间件用户获取IP地址

  def getIpList():

  li=[]

  global count

  url ='http://127.0.0.1:8000/?types=0&count=300'

  ips=requests.get(url)

  for ip in eval(ips.content):

  li.append(ip[0]+':'+ip[1])

  return li

  class ProxyMiddleware():

  global count # 全局变量用于计数

  count=1

  global ips

  ips=[]

  def process_request(self, request, spider):

  # Set the location of the proxy

  global count

  global ips

  if count == 1:

  ips = getIpList() # 调用函数getIPList获取IP

  elif count % 100 == 0:

  ips = []

  ips = getIpList()

  else:

  pass

  try:

  num = random.randint(0, len(ips)) # 获取一个随机IP地址

  ress = 'http://' + ips[num]

  except:

  pass

  else:

  request.meta['proxy'] = str(ress) # 添加代理IP

  count += 1

  在settings.py中添加此中间件

  "tongcheng.middlewares.ProxyMiddleware":100,

  项目案例

  本次我们爬取58同城的二手房为例。本次构建一个master端和一个slave端,master端解析链接存储,slave端根据不同的请求链接获取数据。数据存储到MongoDB中。

  首先创建项目和爬虫(Master)

  scrapy startproject tongcheng

  scrapy genspider tc_zhufang bj.58.com

  from scrapy_redis.spiders import RedisSpider

  from tongcheng.utils.InsertRedis import inserintotc,inserintota

  import re

  class TcZhufangSpider(RedisSpider):

  name = 'tc_zhufang'

  # 解析从start_urls下载返回的页面

  # 页面页面有两个目的:

  # 第一个:解析获取下一页的地址,将下一页的地址传递给爬虫调度器,以便作为爬虫的下一次请求

  # 第二个:获取详情页地址,再对详情页进行下一步的解析

  redis_key = 'start_urls'

  def parse(self, response):

  # 获取所访问的地址

  response_url = re.findall('^http\:\/\/\w+\.58\.com', response.url)

  detail_link_list =response.xpath('//ul[@class="house-list"]/li/@logr').extract()

  next_link = response.xpath(

  '//div[contains(@class,"pager")]/a[contains(@class,"next")]/@href').extract_first()

  if next_link:

  if detail_link_list:

  inserintotc(next_link, 1)

  print('*******[success] the next link ' + next_link + ' is insert into the redis queue*******')

  for detail_link in detail_link_list:

  detail_link = response_url[0] + '/zufang/' + detail_link.split('_')[3] + 'x.shtml'

  if detail_link:

  inserintota(detail_link, 2)

  print('[success] the detail link ' + detail_link + ' is insert into the redis queue')

  Middleware.py

  from random import random

  import requests

  from scrapy.downloadermiddlewares.downloadtimeout import DownloadTimeoutMiddleware

  from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware

  from scrapy.exceptions import IgnoreRequest

  from tongcheng.utils.message import sendMessage_warning

  def getIpList():

  li = []

  global count

  url = 'http://127.0.0.1:8000/?types=0&count=300'

  ips = requests.get(url)

  for ip in eval(ips.content):

  li.append(ip[0] + ':' + ip[1])

  return li

  # Start your middleware class

  class ProxyMiddleware():

  global count # 全局变量用于计数

  count = 1

  global ips

  ips = []

  def process_request(self, request, spider):

  # Set the location of the proxy

  global count

  global ips

  if count == 1:

  ips = getIpList() # 调用函数getIPList获取IP

  elif count % 100 == 0:

  ips = []

  ips = getIpList()

  else:

  pass

  try:

  num = random.randint(0, len(ips)) # 获取一个随机IP地址

  ress = 'http://' + ips[num]

  except:

  pass

  else:

  request.meta['proxy'] = str(ress) # 添加代理IP

  count += 1

  class Redirect_Middleware():

  global count

  count = 1

  def process_response(self, request, response, spider):

  # 处理下载完成的response

  # 排除状态码不是304的所有以3为开头的响应

  http_code = response.status

  if http_code // 100 == 2:

  return response

  if http_code // 100 == 3 and http_code != 304:

  global count

  if count == 1:

  sendMessage_warning()

  print('302')

  count += 1

  # 把request返回到下载器

  return request.replace(dont_filter=True)

  if http_code // 100 == 4:

  # 需要注意403不是响应错误,是无权访问

  raise IgnoreRequest(u'404')

  if http_code // 100 == 5:

  return request.replace(dont_filter=True)

  class RotateUserAgentMiddleware(UserAgentMiddleware):

  """

  a useragent middleware which rotate the user agent when crawl websites

  if you set the USER_AGENT_LIST in settings,the rotate with it,if not,then use the default user_agent_list attribute instead.

  """

  # the default user_agent_list composes chrome,I E,firefox,Mozilla,opera,netscape

  # for more user agent strings,you can find it in http://www.useragentstring.com/pages/useragentstring.php

  user_agent_list = [ 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.43 Safari/537.31',

  'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.60 Safari/537.17',

  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17',

  'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.2; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)',

  'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)',

  'Mozilla/5.0 (Windows; U; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)',

  'Mozilla/6.0 (Windows NT 6.2; WOW64; rv:16.0.1) Gecko/20121011 Firefox/16.0.1',

  'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1',

  'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:15.0) Gecko/20120910144328 Firefox/15.0.2',

  'Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:2.2) Gecko/20110201',

  'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a3pre) Gecko/20070330',

  'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13; ) Gecko/20101203',

  'Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14',

  'Opera/9.80 (X11; Linux x86_64; U; fr) Presto/2.9.168 Version/11.50',

  'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; de) Presto/2.9.168 Version/11.52',

  'Mozilla/5.0 (Windows; U; Win 9x 4.90; SG; rv:1.9.2.4) Gecko/20101104 Netscape/9.1.0285',

  'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.7pre) Gecko/20070815 Firefox/2.0.0.6 Navigator/9.0b3',

  'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080219 Firefox/2.0.0.12 Navigator/9.0.0.6',

  ]

  def __init__(self, user_agent=''):

  self.user_agent = user_agent

  def _user_agent(self, spider):

  if hasattr(spider, 'user_agent'):

  return spider.user_agent

  elif self.user_agent:

  return self.user_agent

  return random.choice(self.user_agent_list)

  def process_request(self, request, spider):

  ua = self._user_agent(spider)

  if ua:

  request.headers.setdefault('User-Agent', ua)

  class Timeout_Middleware(DownloadTimeoutMiddleware):

  def process_exception(self, request, exception, spider):

  # print "####the downloader has exception!"

  print(exception)

  return request.replace(dont_filter=True)

  配置相关

  DOWNLOAD_TIMEOUT=10

  DNSCACHE_ENABLED=True

  #避免爬虫被禁的策略1,禁用cookie

  COOKIES_ENABLED = False

  CONCURRENT_REQUESTS=4

  #CONCURRENT_REQUESTS_PER_IP=2

  #CONCURRENT_REQUESTS_PER_DOMAIN=2

  #设置下载延时,防止爬虫被禁

  DOWNLOAD_DELAY = 5

  #配置日志存储目录

  SCHEDULER = "scrapy_redis.scheduler.Scheduler"

  DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

  SCHEDULER_PERSIST = True

  SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'

  REDIS_URL = None

  REDIS_HOST = '127.0.0.1' # 也可以根据情况改成 localhost

  REDIS_PORT = '6379'

  然后启动redis,

  创建slave端

  scrapy startproject tongcheng_slave

  scrapy genspider tczf_slave bj.58.com

  spider端代码:

  import re

  import scrapy

  from tongcheng_slave.items import TongchengSlaveItem

  class TczfSlaveSpider(scrapy.Spider):

  name = 'tczf_slave'

  redis_key = 'tczufang_tc:requests'

  def parse(self, response):

  tcItem = TongchengSlaveItem()

  response_url = re.findall('^http\:\/\/\w+\.58\.com', response.url)

  # 字段的提取可以使用在终端上scrapy shell进行调试使用

  # 帖子名称

  raw_title = response.xpath(

  u'//div[contains(@class,"house-title")]/h1[contains(@class,"c_333 f20")]/text()').extract_first()

  if raw_title:

  tcItem['title'] = raw_title.encode('utf8')

  # t帖子发布时间,进一步处理

  raw_time = response.xpath(

  u'//div[contains(@class,"house-title")]/p[contains(@class,"house-update-info c_888 f12")]/text()').extract_first()

  if raw_time:

  tcItem['pub_time'] = raw_time

  # 租金

  tcItem['money'] = response.xpath(

  u'//div[contains(@class,"house-pay-way f16")]/span[contains(@class,"c_ff552e")]/b[contains(@class,"f36")]/text()').extract_first()

  # 租赁方式

  raw_method = response.xpath(u'//ul[contains(@class,"f14")]/li[1]/span[2]/text()').extract_first()

  if raw_method:

  tcItem['method'] = raw_method

  # 所在区域

  try:

  area = response.xpath(u'//ul[contains(@class,"f14")]/li[5]/span[2]/a[contains(@class,"c_333")]/text()').extract()[

  1]

  except:

  area = ''

  if area:

  area = area

  try:

  area2 =response.xpath(u'//ul[contains(@class,"f14")]/li[5]/span[2]/a[contains(@class,"c_333")]/text()').extract()[

  2]

  except:

  area2 = ''

  raw_area = area + "-" + area2

  tcItem['area'] = raw_area if raw_area else None

  # 所在小区

  try:

  raw_community =response.xpath(u'//ul[contains(@class,"f14")]/li[4]/span[2]/a[contains(@class,"c_333")]/text()').extract()[

  0]

  tcItem['community'] = raw_community if raw_community else None

  except:

  tcItem['community'] = 0

  # 帖子详情url

  tcItem['targeturl'] = response.url

  # 帖子所在城市

  tcItem['city'] = response.url.split("//")[1].split('.')[0]

  # 帖子的联系电话

  try:

  tcItem['phone'] =response.xpath(u'//div[contains(@class,"house-fraud-tip")]/div[1]/p[3]/text()').extract()[0]

  except:

  tcItem['phone'] = 0

  # 图片1

  try:

  tcItem['img1'] =response.xpath(u'//ul[contains(@class,"pic-list-wrap pa")]/li[1]/@data-src').extract()[0]

  except:

  tcItem['img1'] = 0

  # 图片2

  try:

  tcItem['img2'] = response.xpath(u'//ul[contains(@class,"pic-list-wrap pa")]/li[2]/@data-src').extract()[0]

  except:

  tcItem['img2'] = 0

  yield tcItem

  Items.py

  # -*- coding: utf-8 -*-

  #定义需要抓取存进数据库的字段

  from scrapy.item import Item,Field

  class TcZufangItem(Item):

  #帖子名称

  title=Field()

  #租金

  money=Field()

  #租赁方式

  method=Field()

  #所在区域

  area=Field()

  #所在小区

  community=Field()

  #帖子详情url

  targeturl=Field()

  #帖子发布时间

  pub_time=Field()

  #所在城市

  city=Field()

  # 联系电话

  phone= Field()

  # 图片1

  img1 = Field()

  # 图片2

  img2 = Field()

  Items.py

  import traceback

  from pymongo import MongoClient

  from scrapy.exceptions import DropItem

  class TongchengSlavePipeline:

  def process_item(self, item, spider):

  return item

  class SingleMongodbPipeline(object):

  def __init__(self):

  #初始化mongodb连接

  try:

  client = MongoClient(self.MONGODB_SERVER, self.MONGODB_PORT)

  self.db = client[self.MONGODB_DB]

  except Exception as e:

  traceback.print_exc()

  @classmethod

  def from_crawler(cls, crawler):

  cls.MONGODB_SERVER = crawler.settings.get('SingleMONGODB_SERVER', '101.200.46.191')

  cls.MONGODB_PORT = crawler.settings.getint('SingleMONGODB_PORT', 27017)

  cls.MONGODB_DB = crawler.settings.get('SingleMONGODB_DB', 'zufang_fs')

  pipe = cls()

  pipe.crawler = crawler

  return pipe

  def process_item(self, item, spider):

  if item['pub_time'] == 0:

  raise DropItem("Duplicate item found: %s" % item)

  if item['method'] == 0:

  raise DropItem("Duplicate item found: %s" % item)

  if item['community']==0:

  raise DropItem("Duplicate item found: %s" % item)

  if item['money']==0:

  raise DropItem("Duplicate item found: %s" % item)

  if item['area'] == 0:

  raise DropItem("Duplicate item found: %s" % item)

  if item['city'] == 0:

  raise DropItem("Duplicate item found: %s" % item)

  # if item['phone'] == 0:

  # raise DropItem("Duplicate item found: %s" % item)

  # if item['img1'] == 0:

  # raise DropItem("Duplicate item found: %s" % item)

  # if item['img2'] == 0:

  # raise DropItem("Duplicate item found: %s" % item)

  zufang_detail = {

  'title': item.get('title'),

  'money': item.get('money'),

  'method': item.get('method'),

  'area': item.get('area', ''),

  'community': item.get('community', ''),

  'targeturl': item.get('targeturl'),

  'pub_time': item.get('pub_time', ''),

  'city':item.get('city',''),

  'phone':item.get('phone',''),

  'img1':item.get('img1',''),

  'img2':item.get('img2',''),

  }

  result = self.db['zufang_detail'].insert(zufang_detail)

  print('[success] the '+item['targeturl']+'wrote to MongoDB database')

  return item

  Middlewares.py同master的middlewares.py此处不再重新展现代码

  Settings.py配置

  # 前面的DOWNLOADER_MIDDLEWARES配置内容等同master中的settings.py的配置

  .....

  #单机数据库配置

  SingleMONGODB_SERVER = "127.0.0.1"

  SingleMONGODB_PORT = 27017

  SingleMONGODB_DB = "zufang_fs"

  #设置数据入库pipline

  ITEM_PIPELINES = {

  'tongcheng_slave.SingleMongodbPipeline':300,

  }

  SCHEDULER = "scrapy_redis.scheduler.Scheduler"

  DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

  SCHEDULER_PERSIST = True

  SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'

  REDIS_URL = None

  REDIS_HOST = '127.0.0.1' # 也可以根据情况改成 localhost

  REDIS_PORT = '6379'

  注意:如果需要要先启动Cookies代理池和IP代理池服务器,本案例使用了ip代理池,需要提前启动

  启动项目master

  scrapy runspider tc_zhufang

  启动slave

  scrapy runspider tczf_slave

  启动redis,向redis中添加start_urls

  lpush start_urls https://bj.58.com/chuzu/

  项目案例参考:

相关文章

显著性目标检测和一般目标检测最本质的区别是什么区别?

显著性目标检测和一般目标检测最本质的区别是什么区别?

2023-10-15
在目标检测里single-shot和multi-shot的主要区别是什么?

在目标检测里single-shot和multi-shot的主要区别是什么?

2023-10-15
APP安全测试与普通B/S架构的渗透测试有什么区别?

APP安全测试与普通B/S架构的渗透测试有什么区别?

2023-10-15
什么是域控制器?

什么是域控制器?

2023-10-15

最新文章

常见网络安全面试题:Windows常用的命令有哪些?

常见网络安全面试题:Windows常用的命令有哪些?

2023-10-09
常见网络安全面试题:根据设备告警如何展开排查?

常见网络安全面试题:根据设备告警如何展开排查?

2023-10-09
常见网络安全面试题:mysql加固呢?(数据库加固)

常见网络安全面试题:mysql加固呢?(数据库加固)

2023-10-09
常见网络安全面试题:windows和linux加固?(操作系统加固)

常见网络安全面试题:windows和linux加固?(操作系统加固)

2023-10-09
在线咨询 免费试学 教程领取