爬虫基础篇之页面请求解析

CSS选择器

html中为指定元素指定显示效果,比如颜色,背景,字体等不同的属性,这些样式都是通过css选择器告诉浏览器指定样式风格。

表达式含义
#animal获取id为animal的所有元素
.animal获取class为animal的所有元素
a.active获取类为active的a标签
.animal > .pig获取类animal直接子元素中类为.pig的元素
.animal .pig获取类animal后代元素中类为.pig的元素
a[href*=“animal”]获取包含类animal的a元素
a[href^=“http”]获取href以http开头的a元素
a[href$=“gov.cn”]获取href以gov.cn结尾的a元素
div[class=“animal”][ctype=“pig”]获取多属性同时具备的元素
div > a:nth-child(2)获取div下的第二个a元素
.pig , .animal同时选择两个class的所有元素
p:nth-last-child(1)获取倒数第一个p元素
p:nth-child(even) p:nth-child(odd)获取奇数偶数节点
h3 + span获取h3 后面紧跟着的兄弟节点 span
h3 ~ span获取h3 后面所有的兄弟节点 span

实战

链家

目标抓取网站:https://su.lianjia.com/ershoufang/pg

抓取内容:分页抓取二手房的标题,地址,信息,关注量,标签,总价,单价等

分析

在这里插入图片描述

通过获取网页源代码发现所有的二手房信息都直接渲染在页面上,那么可以直接请求页面地址分析二手房源码后,通过parsel库parsel.Selector(html_data)转为我们可以使用选择器分析的对象。

通过css选择器.clear.LOGCLICKDATA拿到所有的二手房信息所在的li元素

在这里插入图片描述

在li元素下可以css选择器获取所有的.title a::text标题,.positionInfo a::text地址,.followInfo::text关注量等信息。

selector = parsel.Selector(html_data)
lis = selector.css('.clear.LOGCLICKDATA')
for li in lis:
    title = li.css('.title a::text').get()  # 标题
    address = li.css('.positionInfo a::text').getall()  # 地址
    address = ','.join(address)
    houseInfo = li.css('.houseInfo::text').get()  # 信息
    followInfo = li.css('.followInfo::text').get()  # 关注
    tags = li.css('.tag span::text').get()  # 标签
    tags = ','.join(tags)
    totalPrice = li.css('.totalPrice span::text').get() + '万'  # 总价
    unitePrice = li.css('.unitPrice span::text').get()  # 单价
    title_url = li.css('.title a::attr(href)').get()  # 标题
    print(title, address, houseInfo, followInfo, tags, totalPrice, unitePrice, title_url, sep="---")
爬取完成

点击下一页的时候,页面url添加了路径参数pg{},那么可以通过加该字段实现分页抓取。
在这里插入图片描述

猫眼电影

分析

目标抓取网站:https://maoyan.com/board

抓取内容:热映口碑榜的电影名,主演,上映时间等。

老规矩,查看网页源代码电影数据完整返回给前端,没有做异步请求。那么直接访问猫眼的热映口碑榜通过parsel库解析成Selector对象,开始利用css选择器分析页面字段。

通过控制台源码发现类.board-wrapper下dd元素包含了所有的电影信息,那么遍历其下的标签列表根据css选择器筛选拿到需要的数据即可。

selector = parsel.Selector(html_data)
print(selector)
dds = selector.css('.board-wrapper dd')
for dd in dds:
    title = dd.css('.name a::attr(title)').get()
    star = dd.css('.star::text').get().strip()
    releasetime = dd.css('.releasetime::text').get()
    score = dd.css('.score i::text').getall()
    score = ''.join(score)
    print(title, star, releasetime, score)

    with open('maoyan.csv', mode='a', encoding='utf-8', newline='') as f:
        csv_write = csv.writer(f)
        csv_write.writerow([title, star, releasetime, score])
爬取完成

在这里插入图片描述

喜马拉雅

分析

目标网站:https://www.ximalaya.com/xiangsheng/9723091

抓取内容:下载当前主题的所有页面的音频文件。

老规矩,查看网页源代码发现所有的音频标签会在当前页面ur后添加音频的id跳转到一个新的页面,如:https://www.ximalaya.com/xiangsheng/9723091/45982355

点击播放后,控制台的Media出现请求的音频地址,如:https://aod.cos.tx.xmcdn.com/group31/M01/36/04/wKgJSVmC6drBDNayAh_Q8WincwI414.m4a

在这里插入图片描述

通过控制台搜索音频关键字段,找到返回音频地址的请求https://www.ximalaya.com/revision/play/v1/audio?id=46106992&ptype=1

在这里插入图片描述

该请求参数由音频id和ptype=1组成,通过css选择器.sound-list li.lF_ a::attr(href)分析列表页的音频的href拿到音频id,通过css选择器.sound-list li.lF_ a::attr(title)拿到音频标题。点击下一页发现只是在原url后添加p{page}字段,综上通过open函数写入音频文件完成下载。

titles = selector.css('.sound-list li.lF_ a::attr(title)').getall()
href = selector.css('.sound-list li.lF_ a::attr(href)').getall()
# zip() 可以讲两个列表进行打包, 遍历之后 是一个元组
data = zip(titles, href)
for index in data:
    title = index[0]
    mp3_id = index[1].split('/')[-1]
    # f'{mp3_id}'  '{}'.format(mp3_id) 字符串格式化方法
    index_url = f'https://www.ximalaya.com/revision/play/v1/audio?id={mp3_id}&ptype=1'
    response_1 = requests.get(url=index_url, headers=headers)
    # 什么是json数据  字典嵌套字典  还嵌套一些列表
    # json数据取值和字典取值方式是一样的  根据关键词提取内容  通俗的讲 就是根据左边的内容提取右边的内容
    # print(response_1.text)
    mp3_url = response_1.json()['data']['src']
    print(title, mp3_url)
    # 保存数据
    # 保存数据: 如果是图片/音频/视频 等 都是要获取它的二进制数据,要以二进制的数据保存
    mp3_content = requests.get(url=mp3_url).content
    # 相对路径
    with open('相声\\' + title + '.mp3', mode='wb') as f:
        f.write(mp3_content)
        print('正在保存: ', title)
爬取完成

在这里插入图片描述

XPATH选择器

XPath (XML Path Language) 是由国际标准化组织W3C指定的,用来在 XML 和 HTML 文档中选择节点的语言。目前主流浏览器 (chrome、firefox,edge,safari) 都支持XPath语法,xpath有 1 和 2 两个版本,目前浏览器支持的是 xpath 1的语法,且比CSS选择器功能更强大。

表达式含义
/html/body/div选择根节点html下面的body下面的div元素,/从子节点找,//从所有子节点包括子节点的子节点中找
//div/*所有div节点下所有元素
//*[@id=‘west’]id为west的元素
//select[@class=‘single_choice’]class为single_choice的select元素
//p[@class=“capital huge-city”]多元素组合选择
//*[@multiple]具有multiple属性的元素
//*[contains(@style,‘color’)]style包含color的元素
//*[starts-with(@style,‘color’)]以style是color开头的元素,//*[ends-with(@style,‘color’)]结尾元素
//div/p[2]所有div下的第二个p标签
//p[last()]最后一个p元素
//div/p[last()-2]所有div下倒数第三个p元素
//option[position()<=2]option类型的第1-2个元素
//*[@class=‘multi_choice’]/*[position()>=last()-2]选择class属性为multi_choice的后3个子元素
//option|//h4所有的option元素 和所有的 h4 元素
//*[@id=‘china’]/…选择 id 为 china 的节点的父节点
//*[@id=‘china’]/…/…/…上上父节点
//*[@class=‘single_choice’]/following-sibling::div选择后续节点中的div节点 等同于CSS选择器.single_choice ~ *
//*[@class=‘single_choice’]/preceding-sibling::div前面兄弟节点

实战

新笔趣阁

分析

目标网站:http://www.xbiquge.la/10/10489/

抓取内容:抓取三寸人间所有章节的文章保存。

章节列表只有小说章节信息,点击每个章节跳转到章节页面,通常xpath表达式//div[@id="info"]/h1/text()拿到书籍名称,所有的章节都依赖于于id为list的div下的dl下的dd下的a标签的href属性跳转到章节页面。

在这里插入图片描述

拼接主域名http://www.xbiquge.la即可跳转到章节详情页面,通过xpath表达式//*[@id="content"]/text()拿到详情页面小说的完整内容

# 开文件流   打开一个文件 把我们数据写入到文件中去    a是追加写入 写入完第一章就继续追加写入第二章
with open(book_name + '.txt', 'a', encoding='utf-8')as f:
    f.write(book_name+'\n')
    # title 章节的名称     urls 每个章节的详情链接
    # 遍历获取到该本书的每个章节和对应的内容详情链接  zip一次性遍历多个列表
    for title,urls in zip(book_title,book_url):


        c_url='http://www.xbiquge.la'+urls

        print(title)
        print(c_url)

        # 异常处理
        try: #捕捉异常
            #参数1:单个章节的url:以获取到这个章节的小说内容的html源码 参数2:headers  参数3:请求等待时间3秒
            titles_url = requests.get(c_url, headers=headers, timeout=3).content.decode('utf-8')
        except: # 如果捕捉异常怎么办  请求失败那就再请求一遍
            titles_url = requests.get(c_url, headers=headers).content.decode('utf-8')

        # 那我们还差一个小说文本内容对不对 那每个章节链接我们有了
        # 每个章节里面的内容是不是好解决 一样xpath语法给他获取下来
        # 通过xpath获取到小说文本内容
        book_content = etree.HTML(titles_url).xpath('//*[@id="content"]/text()')

        f.write(title) # 先写入章节名称
        f.write('\n')

        # f.write不能够写列表,但可以写字符串格式(二进制)。。。  所以要for循环
        for line in book_content:
            f.write(line) # 再写入章节对应的内容
        f.write('\n')  # 每写完一章换行  一共1000多个章节
爬取完成

在这里插入图片描述

其实很多情况下不需要自己去分析dom节点定位css或xpath表达式,chrome已经为我们集成了插件。

在这里插入图片描述

JSON

很多情况页面不直接返回html或xml文本元素,或者这些文本分析起来很困难的情况下,可以通过控制台中的xhr模式抓取后端请求回来的json数据,直接解析json即可拿到想要的数据。

实战

拉勾

分析

目标网站:https://www.lagou.com/jobs/list_C%2B%2B?labelWords=&fromSearch=true&suginput=

抓取内容:抓取首页职位地址,公司名,规模等信息保存。

搜索C++后,打开控制台将结果中的带薪年假搜索拿到实际请求路径https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false,该请求是post请求,参数如下

data = {
    "first": "true",
    "pn": "1",
    "kd": "C++"
}

在这里插入图片描述

通过控制台Preview分析返回的json数据,data['content']['positionResult']['result']即为职位信息

在这里插入图片描述

不过当我们直接请求时会报dtacess deny,可能对请求头中的参数做了校验。

Traceback (most recent call last):
  File "F:/MyProject/CrawlerBase/lagou/lagou.py", line 21, in <module>
    result = data['content']['positionResult']['result']
KeyError: 'content'
{'clientIp': '61.155.198.*',
 'msg': 'dtaccess deny ',
 'state': 2410,
 'status': False}

我们将Cookie和User-Agent加入header后,即可以完整请求到json数据,进行数据分析。

resp = requests.post(api_url, headers=headers)
pprint(resp.json())
data = resp.json()
result = data['content']['positionResult']['result']
# [print(r) for r in result]
for r in result:
    d = {
        'city': r['city'],
        'companyFullName': r['companyFullName'],
        'companySize': r['companySize'],
        'education': r['education'],
        'positionName': r['positionName'],
        'salary': r['salary'],
        'workYear': r['workYear']
    }
    with open('拉钩职位.csv',mode='a',encoding='utf-8') as f:
        f.write(",".join(d.values()))
        f.write("\n")
爬取完成

在这里插入图片描述

完整源码请关注微信公众号:ReverseCode,回复:爬虫基础

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

onejane

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值