【Python爬虫学习实践】基于Xpath和lxml库解析网站

在之前的学习笔记中,介绍了Xpath语法规则和lxml库的基本使用,同时也列举出了一部分示例代码。为了更加深入地学习和运用好这两大工具,下面以爬取Tencent招聘网站职位信息为实例介绍在实践中基于Xpath和lxml库编写爬虫的基本流程和方法。

Tencent招聘网址:https://hr.tencent.com/

image

进入网站后,我们来浏览一下社会招聘一栏,并输入搜索关键字为’python’,之后方可进入如下页面:

image

此后,在爬取前,我们先任意选择一个职位进入职位详情页,分析一下我们所要爬取的信息有哪些。在如下详情页中我们可以看到欲获取的信息有职位名称、工作地点、职位类别、招聘人数、工作职责和要求。

image

这么一来,爬取需求就已经明确,那么接下来就是分析爬取过程。回顾一下,我们是如何进入职位详情页——在社会招聘先输入关键字后进入职位列表页,然后点击一个职位,浏览器便打开了一个新的url地址,而这也就是职位详情页。因此总体过程是:发送请求获取职位列表页,然后从列表中检索每一个职位详情页的url,再发送新的请求进入详情页,此后便可开展信息提取工作。

第一部分——获取职位详情页url

通过上述分析知,职位详情页url蕴含在职位列表中,所以我们先从职位列表页分析。我们要爬取的是所有职位信息,而这些职位是分布在不同的组(页)中,因此我们先依次点击几页看看这些不同页的url都有什么关联。

经实践后得到如下URL

第2页:https://hr.tencent.com/position.php?lid=&tid=&keywords=python&start=10#a

第3页:https://hr.tencent.com/position.php?lid=&tid=&keywords=python&start=20#a

第4页:https://hr.tencent.com/position.php?lid=&tid=&keywords=python&start=30#a

这里我们可以发现其URL是有一定规律的,它们的大体构成都相同,只是参数start的值不同。经分析后我们可以知道其实start代表的是当前显示职位列表在全部职位中的起始序号,这个与每页显示的职位个数有关,比如每页显示10条,第2页起始为10,那么第3页起始就是10+10=20,第4页就是20+10=30……如此一来,我们就基本上找到了URL的构成法,那么是不是都这样的呢?以第1页为例,按照我们的分析,第1页URL中应该对应的是10-10=0,我们从其他页点击第1页来验证一下,结果发现确实是0,也印证了我们推测的正确性。考虑到后面锚点’#a’对请求无关紧要,因此职位列表URL结构为:’https://hr.tencent.com/position.php?lid=&tid=&keywords=python&start={}’

在此之后我们便可以结合之前学习的Xpath与lxml来获取相应的URL信息。这里我们要注意一点的是在获取href属性时,我们检查元素发现其前面没有域名,同上分析详情页URL我们可以得知其构成法为’域名+href’,故在获取href后需要做适当修改。

image

## 获取职位详情页URL
import requests
from lxml import etree

# 设置请求头
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36'
}

# 设置域名
BASE_DOMAIN = 'https://hr.tencent.com/'

# 定义获取详情页URL函数
def get_detail_page(url):
    response = requests.get(url, headers=HEADERS)
    html = etree.HTML(response.content.decode('utf-8'))
    urls = html.xpath('//table[@class="tablelist"]//tr[@class="even" or @class="odd"]//a/@href')
    detail_page = list(map(lambda url: BASE_DOMAIN + url, urls))
    return detail_page

第二部分——职位详细解析

在获取了每一个职位详情页url后,便可再次发送请求以获取数据。经分析发现数据都存放在了一个table标签里,我们便可先获取这个标签,然后在使用Xpath来解析其他数据。这里解析方法和之前一样,也相对比较简单,这里不再叙述。

image

## 解析详情页面数据
def parse_page(url):
    response = requests.get(url, headers=HEADERS)
    html = etree.HTML(response.content.decode('utf-8'))
    infotable = html.xpath('//table[contains(@class,"tablelist")]')[0]
    info = {
        'title': infotable.xpath('.//td[@id="sharetitle"]//text()')[0],
        'address': infotable.xpath('.//tr[2]/td[1]//text()')[1],
        'category': infotable.xpath('.//tr[2]/td[2]//text()')[1],
        'number': infotable.xpath('.//tr[2]/td[3]//text()')[1],
        'responsibility': ''.join(infotable.xpath('.//tr[3]//ul//text()')),
        'requirement': ''.join(infotable.xpath('.//tr[4]//ul//text()'))
    }
    return info

第三部分——爬虫集成

其实这一部分并不是一个独立的部分,只是运用上述两部分的方法集成为了一个Spider函数供封装使用。

## 爬虫集成
def Spider():
    BASE_URL = 'https://hr.tencent.com/position.php?lid=&tid=&keywords=python&start={}'
    jobs = []
    for index in range(0, 53): #职位列表页数
        url = BASE_URL.format(index * 10)
        #获取详情页URL
        details_urls = get_detail_page(url)
        for page_url in details_urls: 
            #对单独的详情页进行解析
            info = parse_page(page_url)
            jobs.append(info)
            print(info) #为方便显示结果,直接在次进行输出

这么一来,我们便可以在主程序中直接调用Spider()函数实现Tencent招聘职位信息的获取,部分结果如下:

image

以上便是利用Xpath和lxml爬取数据的一个小小实践,主要是为了加深对上述两个工具的理解和运用,其实,这里面还有很多可以完善的地方,如数据的永久化存储以及多进程爬虫等,而这些都还需要后续的多多学习与练习。


原文地址:https://www.cnblogs.com/Unikfox/p/9671239.html