文章目录
上篇
1. xpath案例-百度贴吧(重点)
需求说明:
给定一个贴吧的名字,抓取该贴吧中,第一页中帖子的标题、帖子的详情页url地址,以及帖子详情页中图片的链接,最终要将图片保存到本地。
需要抓取的字段:
- 帖子标题(title)
- 帖子详情页url地址(detail_url)
- 详情页所有图片url地址(img_url_list)
提取数据分析:
# 获取所有帖子的标题
//ul[@id="thread_list"]/li//a[@class="j_th_tit"]/text()
# 获取所有帖子的详情页地址
//ul[@id="thread_list"]/li//a[@class="j_th_tit"]/@href
# 获取帖子详情页图片的地址
//img[@class="BDE_Image"]/@src
代码实现:
import random
import time
import requests
from lxml import etree
class TiebaSpider(object):
"""百度贴吧爬虫类"""
def __init__(self, tb_name):
"""
tb_name: 贴吧的名称
"""
# 准备贴吧 url 地址
self.url = 'https://tieba.baidu.com/f?kw={}'.format(tb_name)
# 准备请求头
self.headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36',
'Cookie': '从浏览器抓包记录中复制的Cookie数据'
}
# 准备详情页基准地址
self.base_url = 'https://tieba.baidu.com'
# 准备保存提取数据的列表
self.data_list = []
def send_request(self, url):
"""发送请求,返回响应"""
# 随机休眠0-1秒
time.sleep(random.uniform(0, 1))
response = requests.get(url, headers=self.headers)
# 返回响应内容
return response.content # bytes
def parse_data(self, html):
"""
提取每个帖子的数据
html:指定贴吧的第一页响应的内容
"""
# 将响应内容中的 html 注释去掉
html_str = html.decode().replace('<!--', '').replace('-->', '')
# 首先把 html_str 内容处理成 Element 对象
element = etree.HTML(html_str)
# 查询包含每个帖子 li 元素
li_list = element.xpath('//ul[@id="thread_list"]/li')
# 遍历每个帖子的 li 元素,提取每个帖子的标题、详情页地址,以及详情页的图片的地址
for li in li_list:
item = {}
# 提取每个帖子的标题
item['title'] = li.xpath('.//a[@class="j_th_tit "]/text()')[0] # list
# 提取每个帖子的详情页地址
item['detail_url'] = li.xpath('.//a[@class="j_th_tit "]/@href')[0]
item['detail_url'] = self.base_url + item['detail_url']
# 提取每个帖子的详情页图片地址
item['img_url_list'] = self.parse_detail(item['detail_url'])
print(item)
# 保存提取帖子的信息
self.data_list.append(item)
def save_data(self):
"""保存帖子详情页图片"""
for item in self.data_list:
# 获取帖子的图片地址列表
img_url_list = item['img_url_list']
for img_url in img_url_list:
# 发送请求
img_response = self.send_request(img_url)
# 保存文件
filename = img_url[-20:]
with open(filename, 'wb') as f:
f.write(img_response)
print(f'{img_url} ---> 图片保存成功!')
def parse_detail(self, url):
"""
解析详情页图片地址
url:帖子的详情页地址
"""
# 先请求获取帖子详情页的内容
detail_response = self.send_request(url)
# 从详情页的内容中提取详情页引入图片的地址
detail_element = etree.HTML(detail_response) # bytes和str
img_url_list = detail_element.xpath('//img[@class="BDE_Image"]/@src')
return img_url_list
def start(self):
"""启动爬虫的方法"""
# 首先要抓取指定贴吧的第一页的内容
html = self.send_request(self.url) # bytes
# 补充:将 html 内容写入文件,验证和浏览器显示的内容是否一致
with open('tieba.html', 'w', encoding='utf8') as f:
f.write(html.decode())
print('文件写入成功!')
# 然后根据响应内容,提取页面上每个帖子的标题、详情页地址,以及详情页的图片的地址
self.parse_data(html)
# 请求详情页图片路径,将图片保存到本地
self.save_data()
if __name__ == '__main__':
# 输入贴吧名称
tb_name = input('请输入贴吧名称:')
# 创建百度贴吧的爬虫类的对象
spider = TiebaSpider(tb_name)
# 启动爬虫
spider.start()
2. BeautifulSoup4使用
Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据,支持css选择器提取数据。
find_all方法:
select方法:
下篇
1. bs4案例-糗事百科爬虫(重点)
页面地址规律分析:
第一页:https://www.qiushibaike.com/text/page/1/
第二页:https://www.qiushibaike.com/text/page/2/
第三页:https://www.qiushibaike.com/text/page/3/
...
第十三页:https://www.qiushibaike.com/text/page/13/
提取每个段子信息分析:
# 查找到包含每个段子信息的 div 标签
div.col1.old-style-col1 > div
# 查找作者
段子的 div 下面 h2 标签文本
# 查找段子内容
段子的 div 下面 class='content' 的 div 标签中的文本
# 查找段子的好笑数
class='stats-vote' 的 span 标签下的 i 标签中的文本
# 查找段子的评论数
class="qiushi_comments" 的 a 标签下的 i 标签中的文本
代码实现:
import json
import random
import time
import requests
from bs4 import BeautifulSoup
class QiuBaiSpider(object):
"""糗事百科爬虫类"""
def __init__(self):
# 准备糗事百科段子页面模板地址
self.base_url = 'https://www.qiushibaike.com/text/page/{}/'
# 准备请求头
self.headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36'
}
# 准备保存段子页面地址的列表
self.url_list = []
# 准备保存段子信息的列表
self.data_list = []
def get_url(self):
"""生成糗事百科段子第1页-13页地址"""
self.url_list = [self.base_url.format(i) for i in range(1, 14)]
def send_request(self, url):
"""发送请求,获取响应"""
# 控制频率
time.sleep(random.uniform(0, 1))
response = requests.get(url, headers=self.headers)
html_str = response.content.decode()
return html_str
def parse_data(self, html_str):
"""响应的 html 数据进行解析"""
# 创建 BeautifulSoup 对象
soup = BeautifulSoup(html_str, 'lxml')
# 查找到包含每个段子信息的 div 标签
div_list = soup.select('div.col1.old-style-col1 > div')
# 遍历每个 div 标签,获取每个段子的信息:作者、内容、好笑数、评论数
for div in div_list:
item = {}
# 查找段子作者
item['author'] = div.find('h2').get_text().strip()
# 查找段子内容
item['content'] = div.find('div', {'class': 'content'}).get_text().strip()
# 查找段子好笑数
item['funny_num'] = div.select('span.stats-vote > i')[0].get_text().strip()
# 查找段子评论数
item['comments'] = div.select('a.qiushi_comments > i')[0].get_text().strip()
# 保存每个段子信息
self.data_list.append(item)
def save_data(self):
"""把提取的数据写入到文件中"""
with open('qiubai.json', 'w', encoding='utf8') as f:
# 将解析后的 list 数据处理格式化字符串
# content = json.dumps(self.data_list, indent=2, ensure_ascii=False)
# f.write(content)
# 上面的两行代码等价于这一句
json.dump(self.data_list, f, indent=2, ensure_ascii=False)
def start(self):
"""启动爬虫的方法"""
# 首先生成糗事百科段子第1页-13页地址
self.get_url()
# 遍历向每一页发送请求,获取每一页段子响应,并对响应的 html 数据进行解析
for url in self.url_list:
# 向每一页发送请求,获取每一页段子响应
html_str = self.send_request(url)
# 对响应的 html 数据进行解析
self.parse_data(html_str)
print(f'{url}------>解析完成!')
# 最后将提取的段子的信息保存到文件中
self.save_data()
if __name__ == '__main__':
# 创建爬虫类的对象
spider = QiuBaiSpider()
spider.start()
2. selenium功能简介
Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,Selenium 可以直接控制浏览器工作。
使用步骤:
1)下载 selenium
包
pip install selenium
2)下载对应浏览器的 webdriver
程序
谷歌浏览器的 webdriver 程序解压之后为:chromedriver
3. selenium 基本使用(重点)
百度搜索示例:
driver对象的常见属性和方法:
driver对象查找标签元素的方法:
find_element_by_id (返回一个元素) find_element(s)_by_class_name (根据类名获取元素列表) find_element(s)_by_name (根据标签的name属性值返回包含标签对象元素的列表) find_element(s)_by_xpath (返回一个包含元素的列表) find_element(s)_by_link_text (根据链接文本获取元素列表) find_element(s)_by_partial_link_text (根据链接包含的文本获取元素列表) find_element(s)_by_tag_name (根据标签名获取元素列表) find_element(s)_by_css_selector (根据css选择器来获取元素列表)
find_element 和 find_elements 的区别:
- 多了个s就返回列表,没有s就返回匹配到的第一个标签对象
- find_element匹配不到就抛出异常,find_elements匹配不到就返回空列表
标签元素对象的属性和方法: