使用scrapy+mysql爬取拉勾网移动端页面

@hcolde字数 4061

使用scrapy+mysql爬取拉勾网移动端页面


前期准备:

  • Python3.6
  • virtualenv ( pip install virtualenv )
  • Scrapy ( pip install Scrapy )
  • PyMySQL ( pip install pymysql )
  • Mysql服务器

1. 搜索职位页面

https://m.lagou.com/search.json?city=广州&positionName=python&pageNo=1

1.1 参数说明:
  • city:搜索的城市
  • positionName:职位名称
  • pageNo:页码

1.2 返回数据:

使用scrapy+mysql爬取拉勾网移动端页面


使用scrapy+mysql爬取拉勾网移动端页面


1.3数据处理:
  • pageSize 每页显示多少个职位信息。 json->content->data->page->pageSize )
  • totalCount 总共有多少个职位。 json->content->data->page->totalCount )
  • positionId 职位id,打开职位详情页面需要的参数,返回的类型为int型。 json->content->data->page->result[]->positionId )

以上是重要的数据,至于其他数据可选择性收集。

根据pageSizetotalCount可计算需要爬取多少个页面,代码如下:

  1. pages = totalPage//pageSize
  2. pages = pages+1 if totalPage%pageSize else pages


1.4 操作数据库
  1. import pymysql
  2. host = '127.0.0.1' # 数据库服务器.
  3. user = 'root' # 数据库用户.
  4. password = '' # 该用户的密码.
  5. dbName = 'lg' # 数据库名.
  6. cursor = None
  7. tyr:
  8. db = pymysql.connect(host=host, user=user, password=password, db=dbName)
  9. except Exception as e:
  10. print(e)
  11. else:
  12. cursor = db.cursor() # 创建游标对象.
  13. # 创建表.
  14. sql = '''
  15. CREATE TABLE IF NOT EXISTS `job`(
  16. `positionId` INT,
  17. `positionName` VARCHAR(50),
  18. `salary` VARCHAR(10),
  19. `createTime` VARCHAR(10),
  20. `companyFullName` VARCHAR(50),
  21. PRIMARY KEY (`positionId`)
  22. )
  23. '''
  24. sql = sql.replace('\t', '').replace('\n', '') # 消掉sql里的制表符和换行符.
  25. if cursor:
  26. try
  27. cursor.execute(sql)
  28. except Exception as e:
  29. print(e)
  30. # 插入数据.
  31. sql = '''
  32. INSERT INTO `job`(
  33. `positionId`,
  34. `positionName`,
  35. `salary`,
  36. `createTime`,
  37. `companyFullName`
  38. ) VALUES (%d, '%s', '%s', '%s', '%s')
  39. ''' % (positionId, name, salary, time, company)
  40. if cursor:
  41. try:
  42. cursor.execute(sql)
  43. db.commit() # 提交到数据库执行.
  44. except Exception as e:
  45. print(e)

2. 职位详情页面

https://m.lagou.com/jobs/1234.html

2.1 参数说明:
  • 该链接中的1234为positionId。


2.2 返回数据:

该链接返回的是html,因此可以使用css选择器或xpath选择器对html中的数据进行采集。

返回的部分html如下:

  1. <div class="detail">
  2. <div class="items">
  3. <span class="item salary"> <em class="icon"></em> <span class="text">8k-15k</span> </span>
  4. <span class="item workaddress"> <em class="icon"></em> <span class="text">北京</span> </span>
  5. <span class="item jobnature"> <em class="icon"></em> <span class="text">全职</span> </span>
  6. <span class="item workyear"> <em class="icon"></em> <span class="text">3-5年</span> </span>
  7. <span class="item education"> <em class="icon"></em> <span class="text"> 学历不限 </span> </span>
  8. </div>
  9. </div>

  1. <div class="content">
  2. <p><strong>岗位职责:</strong>&nbsp;<br />负责Android手机客户端开发。</p>
  3. <br />
  4. <p><br /><strong>任职要求:</strong>&nbsp;<br />1、熟练的Java 编程经验,扎实的计算机知识基础,丰富的实际代码编写经验;&nbsp;<br />2、精通Android系统架构及相关技术,1年以上实际 Android平台开发经验;&nbsp;<br />3、具备团队合作精神,有良好的沟通及协调能力;&nbsp;<br />4、积极主动,具备独立解决问题及自我学习能力。</p>
  5. </div>

2.3 数据处理
  • 获取工作经验信息:
  1. workyear = response.xpath('//div[@class="items"]/span[@class="item workyear"]/span[@class="text"]/text()').extract_first()

  • 获取岗位职责信息:
  1. content = response.xpath('//div[@class="content"]/p/text()').extract()

div[@class="content"]下有多个p标签,所以获取到的信息为列表形式。

html中有多余的制表符,换行符和br标签等等,要将这些去掉。

  1. # str.split()将字符串中所有的空格符作为分隔符,分割为list.
  2. # ''.join(list) 将list以无间隔的形式组合起来.
  3. # 两种方法结合,可去掉多余的制表符,换行符和br标签等空格符.
  4. workyear = ''.join(workyeay.split())
  5. content = ''.join(content) # 因为content为list类型,需要先以无间隔的形式组合成字符串.
  6. content = ''.join(content.split()) # 再用老方法那啥.


2.4 操作数据库
  • 按照1.4的方法创建个job_detail数据表。
  • 从job数据表中获取所有的positionId。
  1. sql = 'SELECT DISTINCT `positionId` FROM `job`'
  2. if cursor:
  3. try:
  4. cursor.execute(sql)
  5. result = cursor.fetchall()
  6. except Exception as e:
  7. print(e)

  • 查看job_detail已保存了哪些职位详情信息。 
    (已保存的就不再爬取)
  1. id_list = []
  2. sql = 'SELECT `positionId` FROM `job_detail`'
  3. if cursor:
  4. try:
  5. cursor.execute(sql)
  6. data = cursor.fetchall()
  7. except Exception as e:
  8. print(e)
  9. else:
  10. for d in data:
  11. id_list.append(d['positionId'])
  • 构建需要爬取的url
  1. urls = []
  2. for r in result:
  3. if r['positionId'] not in id_list:
  4. url = 'https://m.lagou.com/jobs/' + str(r['positionId']) + '.html' # 别忘了positionId是int型.
  5. urls.append(url)

  • 将url交给scrapy
  1. def start_requests(self):
  2. for url in urls:
  3. # dont_Filter默认为False,为True时可重复爬取同一页面,不然scrapy自动帮你无视已爬取的页面.
  4. # 当爬虫不断爬取时,容易被网站服务器拒绝访问,所以当返回的status不为200时,之后再重复爬取该页面.
  5. yield scrapy.request(url=url, dont_filter=True)


默认情况下,Scrapy对响应状态为非20x的页面不进行任何处理。
所以如果要处理响应状态为302,404,502,504这些页面时,需要在爬虫中定义:

  1. handle_httpstatus_list = [302, 404, 407, 502, 504]


结果展示

  1. SELECT positionId, positionName 职位, salary 工资, createTime 发布时间, companyFullName 公司, FROM job;

使用scrapy+mysql爬取拉勾网移动端页面


  1. SELECT
  2. job.companyFullName 公司,
  3. job.positionName 职位,
  4. job.salary 薪资,
  5. job.createTime 发布时间,
  6. job_detail.workyear 工作经验,
  7. substring_index(job_detail.info, '/', -1) 公司相关信息,
  8. left(job_detail.content, 25) 职位描述
  9. FROM job_detail
  10. LEFT JOIN job on job.positionId=job_detail.positionId;

说明
  1. substring_index(str,delim,count): strdelim作为分割符进行截取,获取截取后第count个内容。
  2. left(str, conut): 获取str从左边起的count个字符。

使用scrapy+mysql爬取拉勾网移动端页面

结语

大致的处理过程就是这样,其中还可以开启多线程来存取数据,主线程就爬取网页。

该项目保存地址badboy


版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.****.net/hcolde/article/details/80696841