爬虫基础之爬取豆瓣同城信息(保存为csv excel 数据库)
网站:长沙最近一周戏剧活动_豆瓣
温馨提示: 本案例仅供学习交流使用
requests(发送HTTP请求) | pandas(数据保存模块) |
lxml(用于解析数据模块) | csv(用于保存为csv文件) |
pymysql(用于操作数据库) | parsel(解析数据的模块) |
确定爬取的信息内容:
- 戏剧的名称
- 戏剧的时间
- 戏剧的地点
- 戏剧的费用
- 参与与感兴趣人数
爬取步骤:
- 发送请求 模拟浏览器向服务器发送请求
- 解析数据 提取我们想要的数据
- 保存数据 对数据进行持久化保存 如csv excel mysql
一.发送请求
查看源代码 查看是否为静态数据
打开快捷键 Ctrl+F 输入我们想要爬取的数据
能够搜索到的为 静态数据 不能搜索到的为动态数据由服务器返回的 需要找到相关的返回接口
开始写代码 构建请求
复制浏览器中的网址 请求中的数据在 网络中的标头中查看
url = f'https://www.douban.com/location/changsha/events/week-drama'
F12 or 右击检查 点击网络 Ctrl+R 刷新接口 随便点击一个数据包
这里面包含我们所有的请求信息 比如请求方式 请求地址 UA cookie等
一般我们复制 UserAgent Referer cookie 这三个信息
# 导包
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/133.0.0.0 Safari/537.36 Edg/133.0.0.0',
'referer':
'https://www.douban.com/location/changsha/',
'cookie':
'你的cookie'
}
resp = requests.get(url, headers=headers)
print(resp.text)
打印我们请求到的网页信息 确认需要爬取的数据是否在里面
同样的在终端用Ctrl+F 快捷键打开搜索框 OK 数据在里头
二.解析数据
接着我们解析数据 使用lxml 中的etree模块进行解析
# 将页面解析成html
html = etree.HTML(resp.text)
然后我们分析网页页面 找到包含所有数据的标签 后续通过循环遍历提取
Explain: 用开发者工具上面的小箭头 去页面中分析结构
我们取 ul class属性为events-list events-list-pic100 events-list-psmall 下面的li标签
每一个li标签为一个戏剧
lis = html.xpath('//ul[@class="events-list events-list-pic100 events-list-psmall"]/li')
接着遍历循环 提取数据
name: 直接定位这个itemprop="summary"的span标签 提取里面的文字
for li in lis:
name = li.xpath('.//a/span[@itemprop="summary"]/text()')[0]
# 提取出来的是个列表 我们取出来
time: class属性为event-time的li标签 提取里面的文本
打印查看文本 发现不是我们想要的格式 我们处理成想要的格式
将星期去掉 只保留日期和时间 去除换行符
将列表转换成字符串 去除空格 以一个空格分割
a = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')
打印出来看看结果 split 方法返回的是个列表通过取值得到我们想要的 之后做个字符串的拼接
# 这里我们选择把 星期去掉 只要时间和具体的时间
t = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[0]
i = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[2]
m = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[-3]
e = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[-1]
# 转换成我们想要的格式 中间以||字符隔开
time = t + i + '||' + m + e
时间提取完毕
address:li标签下面meta标签中的itemprop=location 里面的content 属性
但我不要长沙两个字 后续提取的数据中都有 可以像之前那样处理 先转换成字符串 后分割索引取值 做个拼接 这里我一气呵成
address = ''.join(li.xpath('.//li/meta[@itemprop="location"]/@content')).split(' ')[1] + ' ' + \
''.join(li.xpath('.//li/meta[@itemprop="location"]/@content')).split(' ')[2]
接着提取费用: class属性为fee下面的strong标签 里面的文本
去除里面的文字只保留数值
fee = ''.join(li.xpath('.//li[@class="fee"]/strong/text()')).replace('元起', '').replace('元', '')
最后感兴趣人数和参与人数 class属性为counts下面的第一个和第三个span标签 提取里面的文本
与之前的一样 删除文字 只保留数值
# 参与与感兴趣人数
participate = ''.join(li.xpath('.//p[@class="counts"]/span[1]/text()')).replace('人参加', '')
interesting = ''.join(li.xpath('.//p[@class="counts"]/span[3]/text()')).replace('人感兴趣', '')
到此我们所有的数据提取完毕
多页采集的话 分析url请求地址的变化即可
第二页即第四页的数据
我们发现页码从0开始30结束 步长为10
构建循环 遍历
for page in range(0, 31, 10):
url = f'https://www.douban.com/location/changsha/events/week-drama?start={page}'
三.保存数据
先将我们的数据保存到字典当中 在外面定义一个空列表 后续将字典添加到列表中
# 主体代码如下
data = []
for page in range(0, 31, 10):
url = f'https://www.douban.com/location/changsha/events/week-drama?start={page}'
headers = {
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0',
'referer':
'https://www.douban.com/location/changsha/',
'cookie':
'bid=BY8EGmm9qc8; _vwo_uuid_v2=D1D9F5E9C68A518ED23DD0F263091E11E|05339352015c3656f34b21db6f6d7fac; _pk_id.100001.8cb4=273b64a736ae847b.1740225141.; dbcl2="287338786:YzuvHMiOWzs"; push_noty_num=0; push_doumail_num=0; __yadk_uid=PRahUgXe0eJLiRZgpFZjUYaLI78zwXW2; __utmv=30149280.28733; _ga_RXNMP372GL=GS1.1.1741225615.2.0.1741225615.60.0.0; ck=qsD8; __utmc=30149280; __utmz=30149280.1741595670.20.11.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/; frodotk_db="5213e2611a4c65c4f63ba7234ee5314c"; _ga=GA1.2.1489580265.1740970320; _gid=GA1.2.1344269174.1741598633; _ga_Y4GN1R87RG=GS1.1.1741598632.1.0.1741598634.0.0.0; loc-last-index-location-id="118267"; ll="118267"; ap_v=0,6.0; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1741606351%2C%22https%3A%2F%2Fntp.msn.cn%2F%22%5D; _pk_ses.100001.8cb4=1; __utma=30149280.1636982792.1735051587.1741598189.1741606351.22; __utmt=1; __utmb=30149280.4.10.1741606351'
}
resp = requests.get(url, headers=headers)
html = etree.HTML(resp.text)
lis = html.xpath('//ul[@class="events-list events-list-pic100 events-list-psmall"]/li')
dit = {}
for li in lis:
name = li.xpath('.//a/span[@itemprop="summary"]/text()')[0]
# 这里我们选择把 星期去掉 只要时间和具体的时间
t = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[0]
i = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[2]
m = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[-3]
e = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[-1]
# 转换成我们想要的格式
time = t + i + '||' + m + e
# 另外一种方法 处理时间
# n = li.xpath('.//li[@class="event-time"]/text()')[1].replace('\n', '').replace(' ','')
# address = ''.join(li.xpath('//ul[@class="event-meta"]/li[2]/text()')).replace('\n','').replace(' ','')
# 电影费用 并只保留数值
# 将前面的长沙去掉
address = ''.join(li.xpath('.//li/meta[@itemprop="location"]/@content')).split(' ')[1] + ' ' + \
''.join(li.xpath('.//li/meta[@itemprop="location"]/@content')).split(' ')[2]
fee = ''.join(li.xpath('.//li[@class="fee"]/strong/text()')).replace('元起', '').replace('元', '')
# 参与与感兴趣人数
participate = ''.join(li.xpath('.//p[@class="counts"]/span[1]/text()')).replace('人参加', '')
interesting = ''.join(li.xpath('.//p[@class="counts"]/span[3]/text()')).replace('人感兴趣', '')
dit = {
'name': name,
'time': time,
'fee': fee,
'participate': participate,
'interesting': interesting,
'address': address,
}
data.append(dit)
pd.DataFrame(data).to_excel('city.xlsx', index=False)
以上为通过pandas保存为excel表格
保存为csv 文件方式
# 导入模块
import csv
#调用字典写入方法 写入文件 保存为csv的格式编码为utf-8-sig 不然会出现乱码
csv_writer = csv.DictWriter(open('city_csv.csv', 'w', encoding='utf-8-sig', newline=''),
fieldnames=['name', 'time', 'fee', 'participate', 'interesting', 'address'])
# fieldnames 定义标头
# 写入表头
csv_writer.writeheader()
保存到数据库
前提需要建库建表 定义字段
# 导包
import pymysql
# 获取连接
connect = pymysql.connect(user='root',
password="112233",
host='localhost',
database='douban', )
# 拿到游标
cursor = connect.cursor()
# 准备sql语句
sql = 'insert into city values(%s,%s,%s,%s,%s,%s)'
# 执行sql
cursor.executemany(sql, [(name, time, fee, participate, interesting, address)])
# 提交事务
connect.commit()
本次案例的所有源代码 供大家交流学习使用
import requests
from lxml import etree
import pandas as pd
import csv
import pymysql
# csv_writer = csv.DictWriter(open('city_csv.csv', 'w', encoding='utf-8-sig', newline=''),
# fieldnames=['name', 'time', 'fee', 'participate', 'interesting', 'address'])
# csv_writer.writeheader()
# 获取连接
connect = pymysql.connect(user='root',
password="112233",
host='localhost',
database='douban', )
cursor = connect.cursor()
data = []
for page in range(0, 31, 10):
url = f'https://www.douban.com/location/changsha/events/week-drama?start={page}'
headers = {
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0',
'referer':
'https://www.douban.com/location/changsha/',
'cookie':
'bid=BY8EGmm9qc8; _vwo_uuid_v2=D1D9F5E9C68A518ED23DD0F263091E11E|05339352015c3656f34b21db6f6d7fac; _pk_id.100001.8cb4=273b64a736ae847b.1740225141.; dbcl2="287338786:YzuvHMiOWzs"; push_noty_num=0; push_doumail_num=0; __yadk_uid=PRahUgXe0eJLiRZgpFZjUYaLI78zwXW2; __utmv=30149280.28733; _ga_RXNMP372GL=GS1.1.1741225615.2.0.1741225615.60.0.0; ck=qsD8; __utmc=30149280; __utmz=30149280.1741595670.20.11.utmcsr=cn.bing.com|utmccn=(referral)|utmcmd=referral|utmcct=/; frodotk_db="5213e2611a4c65c4f63ba7234ee5314c"; _ga=GA1.2.1489580265.1740970320; _gid=GA1.2.1344269174.1741598633; _ga_Y4GN1R87RG=GS1.1.1741598632.1.0.1741598634.0.0.0; loc-last-index-location-id="118267"; ll="118267"; ap_v=0,6.0; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1741606351%2C%22https%3A%2F%2Fntp.msn.cn%2F%22%5D; _pk_ses.100001.8cb4=1; __utma=30149280.1636982792.1735051587.1741598189.1741606351.22; __utmt=1; __utmb=30149280.4.10.1741606351'
}
resp = requests.get(url, headers=headers)
html = etree.HTML(resp.text)
lis = html.xpath('//ul[@class="events-list events-list-pic100 events-list-psmall"]/li')
dit = {}
for li in lis:
name = li.xpath('.//a/span[@itemprop="summary"]/text()')[0]
# 这里我们选择把 星期去掉 只要时间和具体的时间
t = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[0]
i = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[2]
m = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[-3]
e = ''.join(li.xpath('.//li[@class="event-time"]/text()')).strip().split(' ')[-1]
# 转换成我们想要的格式
time = t + i + '||' + m + e
# 另外一种方法 处理时间
# n = li.xpath('.//li[@class="event-time"]/text()')[1].replace('\n', '').replace(' ','')
# address = ''.join(li.xpath('//ul[@class="event-meta"]/li[2]/text()')).replace('\n','').replace(' ','')
# 电影费用 并只保留数值
# 将前面的长沙去掉
address = ''.join(li.xpath('.//li/meta[@itemprop="location"]/@content')).split(' ')[1] + ' ' + \
''.join(li.xpath('.//li/meta[@itemprop="location"]/@content')).split(' ')[2]
fee = ''.join(li.xpath('.//li[@class="fee"]/strong/text()')).replace('元起', '').replace('元', '')
# 参与与感兴趣人数
participate = ''.join(li.xpath('.//p[@class="counts"]/span[1]/text()')).replace('人参加', '')
interesting = ''.join(li.xpath('.//p[@class="counts"]/span[3]/text()')).replace('人感兴趣', '')
dit = {
'name': name,
'time': time,
'fee': fee,
'participate': participate,
'interesting': interesting,
'address': address,
}
# data.append(dit)
# csv_writer.writerow(dit)
sql = 'insert into city values(%s,%s,%s,%s,%s,%s)'
cursor.executemany(sql, [(name, time, fee, participate, interesting, address)])
connect.commit()
# pd.DataFrame(data).to_excel('city.xlsx', index=False)
本次的案例到此结束 感谢大家的观看 您的点赞和关注是我更新的动力
也可以看看我之前的文章希望对你有帮助