|
scrapy基础部分就不再做解析了,请移步:scrapy中文文档 https://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/overview.html
此次对scrapy应用是基于二次开发的,利用scrapy的框架的爬取大致流程,自己独立写模块,可以使开发流程更为简洁明了,降低了程序内部耦合,在实际应用过程中有一定的通用性, 而又不拘泥于scrapy原生的语法。
接下来分析一下我的scrapy,spider部分的结构
class lagouSpider(scrapy.Spider):
handle_httpstatus_list = [500,503, 504, 400, 403, 404, 408]
name = "lagou"
allowed_domains = ["lagou.com"]
start_urls = [(url_prefix.format(i) , i, 'company') for i in range(1, 180000)]
def make_requests_from_url(self,url):
request = scrapy.Request(url[0], callback=self.handle_parse,errback = self.handle_error)
request.meta['index'] = url[1]
request.meta['type'] = url[2]
return request
要点:
1.当make_requests_from_url函数存在时,自动执行,将start_urls的每一个元素传入该函数,该元素类型可以为多种,本例中格式为列表, 目的是方便传入url内容的类型(如:公司,职位), 将其保存为meta
2.我们利用meta来传递一些用于标识的数据, 例如在拉勾网中,我们要爬取的公司的id,职位的类型和页码
def handle_parse(self, response):
baseinfo = {'index':response.meta['index']} #这里baseinfo用来保存到本地文件中,后续我们将往里添加各种信息
maininfo = parse_company(response) #parse_company是独立写的解析模块中的函数,源代码见GitHub
if 'err' in maininfo: #解析中遇到错误时会有err信息,没有的话说明解析正确,继续执行
info = {}
info['index'] = baseinfo['index']
info['type'] = response.meta['type']
info['err'] = maininfo['err']
#baseinfo['type'] = "NotFound"
if maininfo['err']=='404 NotFound':
self.f_404.write(json.dumps(info))
self.f_404.write('\n')
else:
self.f_retry.write(json.dumps(info))
self.f_retry.write('\n')
else:
info={}
info['index']= baseinfo['index']
info['type']='company'
info['data']=maininfo
self.f_success.write(json.dumps(info)) #将收集到的公司的信息保存为json格式,该格式便于阅读和分析
self.f_success.write('\n')
self.f_success.flush() #将内存里的数据写入硬盘,可以在爬取的过程中读取
postCount = maininfo['dataInfo']['positionCount'] #postCount是统计该公司的职位数量
if postCount!=0: #如果职位数量不为0,分类查找岗位
for i in ['技术','产品','运营','市场与销售','职能','金融','设计']:
url_post_prefix = "https://www.lagou.com/gongsi/searchPosition.json?companyId={}&positionFirstType={}&pageNo={}&pageSize=10"
url = url_post_prefix.format(baseinfo['index'], i, 1) #生成新的url及相关信息,这里的url包含了岗位类型,url,和页数
request = scrapy.Request(url,cookies=cookie, callback=self.handle_parse_post, errback = self.handle_error) #这里要爬取的类型为职位,回调函数设置为handle_parse_post
request.meta['type'] = 'post'
request.meta['index'] = baseinfo['index']
request.meta['postType'] = i
request.meta['pageNo'] = 1
yield request #这里利用yield,将request传给回调函数的同时函数继续运行
print 'company:{}正在加载,岗位类型为{},当前岗位第{}页'.format(baseinfo['index'], i, 1)
|
|