赞
踩
声明:仅供技术交流,请勿用于非法用途,如有其它非法用途造成损失,和本博客无关
废话不多说,直接开始吧~
本次爬取的网站是:点击跳转
我们随便筛选几个条件搜索一下,发现了这个列表页的url是存在一定规律的:
例如:筛选的条件为广东的18岁以上的mm:
http://www.youyuan.com/find/guangdong/mm18-0/advance-0-0-0-0-0-0-0/p1/
例如:筛选的条件为广东的18岁至25岁的mm:
http://www.youyuan.com/find/guangdong/mm18-25/advance-0-0-0-0-0-0-0/p1/
其次,按F12打开开发者工具,然后可以看到这一列表页上的所有信息都在<ul class="mian search_list">
下的<li>
当中,并且可以发现详情页的url就在a标签里面。
拿到了详情页的url后,接下来就是翻页的url,以及什么时候停止翻页了,我们将页面滚动到最低端,找到>
这个翻页的按钮,可以发现其href属性就是翻页的url。并且还发现了,当不能进行翻页时,这个herf属性的值变成了###
。
接下来,进入详情页里面获取我们需要的信息了。发现html的结构还是很有规则的,很容易就能获取到所需要的信息。(这里就不多讲了,详情请看代码以及注释即可)
全国所有城市中18岁以上的mm,这个页面里包含了所有城市对应的部分url链接,用于拼接搜索条件的具体的url链接即可。
首先创建Scrapy爬虫项目:scrapy startproject youyuan
然后再创建爬虫文件:cd youyuan && scrapy genspider yy youyuan.com
最后开始敲代码
(一)原始Scrapy框架下的爬虫代码(非分布式)
items.py 代码如下:
from scrapy import Item, Field
class YouyuanItem(Item):
name=Field() #姓名
address = Field() #地址
age = Field() #年龄
height = Field() #身高
salary = Field() #收入
house = Field() #房子
hobby = Field() #爱好
image = Field() #照骗
motto = Field() #内心独白
detail = Field() #详细资料
boy_condition = Field() #男友标准
url=Field() #个人主页
pipelines.py 代码如下:(开发阶段只先输出一下,没有特别的地方)
# -*- coding: utf-8 -*-
# Define your item pipelines here
class YouyuanPipeline(object):
def process_item(self, item, spider):
if spider.name == 'yy':
print(item)
return item
yy.py 代码如下:
# -*- coding: utf-8 -*- import scrapy from youyuan.items import YouyuanItem import re # 这个函数是用于处理详细资料和征友条件的,返回一个字典 def process_data(data): key = data[::2] value = [re.sub(' ','',i) for i in data[1::2]] return dict(zip(key, value)) class YySpider(scrapy.Spider): name = 'yy' allowed_domains = ['youyuan.com'] start_urls = ['http://www.youyuan.com/city/'] def parse(self, response): # 构造每个城市中的18岁以上的mm请求url base_url = 'http://www.youyuan.com/find{0}mm18-0/advance-0-0-0-0-0-0-0/p1/' a_list=response.xpath('//div[@class="yy_city_info"]/ul/li/font/a') for a in a_list: yield scrapy.Request( base_url.format(a.xpath('./@href').get()), callback=self.parse_all, priority=3 ) def parse_all(self, response): # 拿到列表页中所有mm的详情页url li_list = response.xpath('//ul[@class="mian search_list"]/li') for li in li_list: detail_url = response.urljoin(li.xpath('./dl/dt/a/@href').get()) yield scrapy.Request( detail_url, callback=self.parse_item, priority=1 ) # 若有下一页,则继续发起请求 temp = response.xpath('//a[@class="pe_right"]/@href').get() if temp != '###': next_page = response.urljoin(temp) yield scrapy.Request( next_page, callback=self.parse_all, priority=2 ) def parse_item(self, response): # 详情页里爬取mm的所有想要的信息 # 判断是否已经进入了详情页,有一些页面会重定向到首页,从而会报错的 flag=response.xpath('//p[@class="top_tit"]') if flag: item=YouyuanItem() item['name'] = response.xpath('//div[@class="main"]/strong/text()').get() # 姓名 temp=response.xpath('//p[@class="local"]/text()').get().split() item['address'] = temp[0] # 地址 item['age'] = temp[1] # 年龄 item['height'] = temp[2] # 年龄 item['salary'] = temp[3] # 收入 item['house'] = temp[4] # 房子 item['hobby'] = [i.strip() for i in response.xpath('//ol[@class="hoby"]/li//text()').getall()] # 爱好 item['image'] = response.xpath('//li[@class="smallPhoto"]/@data_url_full').getall() # 照骗 item['motto'] = response.xpath('//ul[@class="requre"]/li[1]/p/text()').get().strip() # 内心独白 item['detail'] = process_data(response.xpath('//div[@class="message"]')[0].xpath('./ol/li//text()').getall()) # 详细资料 item['boy_condition'] = process_data(response.xpath('//div[@class="message"]')[1].xpath('./ol/li//text()').getall()) # 男友标准 item['url'] = response.url # 个人主页 return item
settings.py 代码如下:
# -*- coding: utf-8 -*- # Scrapy settings for youyuan project BOT_NAME = 'youyuan' SPIDER_MODULES = ['youyuan.spiders'] NEWSPIDER_MODULE = 'youyuan.spiders' # 日志级别 LOG_LEVEL='DEBUG' # 用户代理 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36' # Obey robots.txt rules ROBOTSTXT_OBEY = False # 下载延迟 DOWNLOAD_DELAY = 0.5 # pipeline管道 ITEM_PIPELINES = { 'youyuan.pipelines.YouyuanPipeline': 300, }
(二)Scrapy-Redis(分布式爬虫)
其实应用Scrapy-Redis框架来写分布式爬虫,只需要在原始Scrapy框架下的爬虫代码里修改一部分代码即可。
from scrapy_redis.spiders import RedisSpider
# class YySpider(scrapy.Spider):
class YySpider(RedisSpider):
name = 'yy'
allowed_domains = ['youyuan.com']
# start_urls = ['http://www.youyuan.com/city/']
redis_key = 'yy:start_urls'
# 去重 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 优先级队列(以下3个随便选一个) # SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue" SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue" #SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack" # 允许暂停 SCHEDULER_PERSIST = True # Redis连接 REDIS_HOST = 'master机的ip地址' REDIS_PORT = 6379 REDIS_PARAMS = {'password':'redis设置的密码'} # 没有配置密码的话可以去掉 # 并发请求数量(默认是16,若不更改小一点的话,会出现有一台机一直处于等待状态) CONCURRENT_REQUESTS = 2 # pipeline管道(开启redis的管道) ITEM_PIPELINES = { 'youyuan.pipelines.YouyuanPipeline': 300, 'scrapy_redis.pipelines.RedisPipeline': 400, }
首先,在master机上开启redis服务端,即在控制台运行命令:redis-server
,或者以指定配置文件的方式来启动:redis-server /etc/redis/redis.conf
然后,在master机上的另一个终端上进入redis客户端,即在控制台运行命令:redis-cli
,之后如果你的redis设置了密码,那么再输入:auth 你的密码
,然后才能继续操作redis数据库
再者,分别运行两台机的爬虫项目(不分先后,随意即可),运行的命令是:scrapy crawl yy
(在有scrapy.cfg文件的目录下进入cmd命令),此时两台机都是处于监听的状态中
最后,在master机的redis客户端中,输入:lpush yy:start_urls http://www.youyuan.com/city/
,之后,会看到两台机都开始跑起来了!ohhhhhhhhhhh~
即使爬取到的数据会自动存到Redis数据库中(开启Redis的pipeline之后),可是我的云服务器内存还是比较小,不想占用太多的内存,所以,可以将Redis数据库中的数据转存到本地MySQL数据库中。
Python中操作Redis数据库的包是:redis
,可以直接用pip来安装;而操作MySQL数据库的包是:pymysql
,同样可以用pip来安装。
将数据转存到MySQL的代码如下:
import json import redis import pymysql import time # 连接redis数据库 rediscli = redis.StrictRedis(host='', port = 6379, db = 0, password='') # 连接mysql数据库 mysqlcli = pymysql.connect(host='',user='',password='',database='',charset='utf8') while True: if rediscli.exists("yy:items") == 0: sj = time.perf_counter() # 计时 # 超过1分钟,退出循环 if sj >= 60: mysqlcli.close() break else: # 将Redis数据库中的数据pop出来 source, data = rediscli.blpop(["yy:items"]) item = json.loads(data) cursor = mysqlcli.cursor() sql = '''insert into youyuan(name,address,age,height,salary,house,hobby,image,motto, detail,boy_condition,url) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)''' cursor.execute(sql,[item['name'],item['address'],item['age'],item['height'],item['salary'],item['house'], json.dumps(item['hobby'],ensure_ascii=False), json.dumps(item['image'],ensure_ascii=False), item['motto'],json.dumps(item['detail'],ensure_ascii=False), json.dumps(item['boy_condition'],ensure_ascii=False),item['url']]) mysqlcli.commit() cursor.close()
tar -cvf youyuan.tar youyuan
(在youyuan项目的最上层文件目录下进入cmd命令,再运行即可);然后在云服务器上的解包命令:tar -xvf youyuan.tar
即可;其中,将打包后项目上传到云服务器上可以在xshell里面操作。WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
这时,只需按照它的提示在这个/etc/sysctl.conf
配置文件中加入vm.overcommit_memory = 1
,并且在控制台中运行命令:sysctl vm.overcommit_memory=1
即可。ps:扫描下方二维码,关注公众号【Python王者之路】,回复20200626
即可获取本文项目源代码
https://www.bilibili.com/video/BV1H441127tZ
其实一开始我是用RedisCrawlSpider
来爬的,可是呢,如果只是一台机运行的话,master和salve都可以跑,没问题的,但是,一旦两台机一起跑,就会有其中一台机跑不了,报错的信息是builtins.ValueError:Method '_callback' not found
,不是callback找不到就是其他的函数,总之总有一台机跑不了(百度了很久,也没有解决。),本来我都想放弃了,然后突然有个想法就是不用RedisCrawlSpider
来爬,换成RedisSpider
,之后竟然奇迹般地成功了!!哈哈哈哈~
这个是补全之前的Scrapy框架的学习心得,其实在那个时候就知道分布式爬虫的一些原理了,只是没有去实践。所以,现在有时间了,就补上了之前学习Scrapy框架未完成的事。还是会学到很多东西的哈哈~
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。