Web搜索技术python爬虫学习记录
- python数据爬取学习全记录
- pycharm的安装
- request模块学习
- beautifulsoup学习
- 反爬虫与反反爬虫
- 学习案例——爬取豆瓣电影榜单top250
- 作业——爬取b站某搜索关键词的的1000个视频数据
python数据爬取学习全记录
pycharm的安装
一开始我是用的anaconda里的spider来编写,但是电脑本身又装了python3.9,anaconda中是3.7,在配置环境的时候总容易搞糊涂,所以还是采用了pycharm来编写。
安装配置参考链接:https://www.runoob.com/w3cnote/pycharm-windows-install.html
request模块学习
1、 获取网页代码
import requests
url = "http://www.baidu.com"
html = requests.get(url)
print(html)
运行得:
出现报错:返回值200 <respond [200]>
解决:
添加解决头参数User-Agent2、 User-Agent
参考:
(1) F12查看想要获取的网页代码,本机自带Microsoft edge如下
黄框内表示浏览器发送的各种请求,任意点开一个,可以看到左边的扩展栏,点击蓝框标头,可以在下方找到User-Agent
找到头参数后,修改代码如下:
import requests
url = "http://www.baidu.com"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'}
html = requests.get(url, headers=headers)
print(html)
但是此时还会出现报错:返回值200 <respond [200]>
这时还需修改print为html.text,即:
import requests
url = "http://www.baidu.com"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'}
html = requests.get(url, headers=headers)
print(html)
print('***')
print(html.text)
运行得到结果:
beautifulsoup学习
通过以下文档学习基本用法,感受该函数的功能:
https://cuiqingcai.com/1319.htmlhttps://blog.csdn.net/kikaylee/article/details/56841789https://www.jianshu.com/p/8bb16b577a9f 通过以上的学习,可以学习到如何抓取网页代码中标签中的内容
反爬虫与反反爬虫
1、 反爬虫
反爬虫的常见手段大概有以下这些:
(1) 不返回网页,如不返回内容和延迟网页的返回时间
不返回网页是一种比较传统的反爬虫手段,也就是网站对爬虫请求返回
404 或者长时间不返回数据。
由于正常人在一般情况下不会短时间内访问大量网站,所以网站会根据IP 的访问量进行一定的封杀。
session 中会存储特定用户的属性和配置信息,当用户在 web 页面之间来回跳转时,session 的变量不会丢失,而如果一个 session 的访问量过大,也可能会遭到封杀。
当然,正如在第二部分提到的,User-Agent 识别也是一种最基础的封杀手段。
(2) 返回数据非目标网页,如返回错误页,返回空白页和爬取多页时间均返回同一页
很多时候,我们虽然能够爬取目标网站,但是爬虫返回的很可能是一个假的数据,比如返回空白页,或者返回的数据与网站显示的不一样等
(3) 增加获取数据的难度,如登录才可查看和登录时设置时间
最直接的就是将页面中的内容设置为登录后才可查看,然后可以在登录界面加入图形验证码等手段增加反爬难度
2、 反反爬虫
(1)修改请求头User-Agent
(2)增加爬虫时间间隔
利用Time库完成
import time
for i:
spider(i)
# 这 里 是 一 段 伪 代 码, spider(i)是 具 体 的 爬 虫 代 码
time.sleep(10)
(3)使用代理
为了避免单个 IP 多次爬取导致被封,还可以使用 IIP 代理,示例如下:
import requests
link = "http://www.baidu.com"
proxies = {'http': 'http://xxx.xxx.xxx.xxx'} # 可 以 通 过 搜 索 引 擎 搜 索 的 方 式 自 行 获 取IP代 理 池
response = requests.get(link, proxies=proxies)
在做老师给的案例以及作业时,页相应出现过很多次3xx以及4xx,在仔细看了老师给的以上资料后,加入了User_Agent以及headers后有效解决了问题,虽然在作业中,一旦爬取一次后,就有很大可能接下来出现页响应412的错误,但是只要等待几分钟后又可继续爬取。
学习案例——爬取豆瓣电影榜单top250
可以参考一下链接以加强理解:
https://www.pianshen.com/article/7397136077/https://blog.csdn.net/qq_39226755/article/details/83684361https://www.jianshu.com/p/8a460be5a26ehttps://blog.csdn.net/xing851483876/article/details/80578998
1、 直接通过print展示电影名称
import requests
from bs4 import BeautifulSoupdef
get_movies():
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'}
movie_list = []
for i in range(0, 10): #range()创建一个整数列表 0 1 2 .....9
link = 'https://movie.douban.com/top250?start=' + str(i * 25) #一页只能展示出25个电影,所以每25个重新显示一次
#print(link)
r = requests.get(link, headers=headers, timeout=10) #得到网页代码
#print(r.text)
print(str(i + 1), "页 响 应 状 态 码:", r.status_code) #页响应状态码200表示OK客户端请求成功
soup = BeautifulSoup(r.text, "lxml") #将html解析为对象进行处理,全部页面转变为字典或者数组
#print(soup)
div_list = soup.find_all('div', class_='hd') #查找所有class属性为hd的div标签
#print(div_list)
for each in div_list:
movie = each.a.span.text.strip() #获取class属性为hd的div标签的a标签的第一个span标签的文本
movie_list.append(movie)
return movie_list
get_movies()print(get_movies())
运行结果:
可以看到每一页抓取的页响应状态都是200,表示抓取正常。
最后输出movies_list[]
2、 输出结果到txt文件,并加入电影具体信息
import requests
from bs4 import BeautifulSoup import json
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0'}
# 筛选信息
def get_top(url):
respose = requests.get(url, headers=headers)
soup = BeautifulSoup(respose.text, 'lxml')
nums = soup.select('em')
titles = soup.find_all('div', class_='hd')
actors = soup.find_all('p', class_='')
links = soup.select('ol li div a')
rating_nums = soup.find_all('span', class_='rating_num')
evaluate_numbers = soup.find_all('div', class_='star')
evaluates = soup.find_all('span', class_='inq')
# 将信息放进字典中
for num, title, link, actor, rating_num, evaluate_number, evaluate in zip(nums, titles, links, actors, rating_nums,
evaluate_numbers, evaluates):
data = { # 获取节点文本
'排行': num.get_text(),
'电影名字': title.get_text().split('\n')[2],
'链接': link.get('href'),
'导演人员': actor.get_text().strip(),
'评分': rating_num.get_text().strip(),
'评价人数': evaluate_number.get_text().split('\n')[4],
'评价内容': evaluate.get_text()
}
print(data)
# 写入文件
file = open(r'D:\web_homework_1\douban.txt', 'a', encoding='utf-8')
for k, v in data.items():
s2 = str(v)
file.write(k + ' ')
file.write(s2 + ' ')
file.write('\n')
file.close
if __name__ == '__main__':
# 多页爬取
for i in range(11):
urls = {'https://movie.douban.com/top250?start={}&filter='.format(i * 25)}
# 遍历
for url in urls:
get_top(url)
运行结果
注意:因为写入文件时设置的参数是a而不是w,所以每次写入并不会覆盖上一次的结果,会接着上一次的结果重复写入,可以通过在文件名命名时加入time使得每次输出文件名不同。具体应用见作业。
txt文件:
作业——爬取b站某搜索关键词的的1000个视频数据
代码
#引入库
import requests
from bs4 import BeautifulSoup
import json
import time
#设置hesders反爬虫,还可以在后面加Host参数,但是本次作业中没有用到也可以
headers = {
'User-Agent': 'Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 52.0.2743.116Safari / 537.36Edge / 15.15063'
}
#抓取网址
#以下代码中的网址https://search.bilibili.com/video?keyword=%E5%B1%B1%E6%B2%B3%E4%BB%A4&order=totalrank&duration=0&tids_1=0&page=1
#表示搜索山河令后按综合排序的第一页
#如下示代码,修改page后的数字可以获取不同页的网页代码,依次解析,逐个分析即可获取想要数据。
#(1)若想要限制视频时长,可以修改duration的值,0表示全部时长,1表示10分钟以下,2表示10-30分钟,3表示30-60分钟,4表示60分钟以上。
#(2)若想限制视频分区,可以修改tids_1的值,0表示全部分区,1表示动画,13表示番剧,167表示国创,3表示音乐,129表示舞蹈,4表示游戏,36表示知识,188表示数码,160表示生活,211表示美食,217表示动物,119表示鬼畜,155表示时尚,202表示资讯,5表示娱乐,181表示影视,177表示纪录片,23表示电影,11表示电视剧。
#(3)若想修改排序方式,则修改order的值:
#order=totalrank 综合排序
#order=click 点击量
#order=pubdate 最新发布
#order=dm 弹幕数
#order=stow 收藏量
# 筛选信息
def get_top():
movie_list = []
for i in range(0, 50):
link = 'https://search.bilibili.com/video?keyword=%E5%B1%B1%E6%B2%B3%E4%BB%A4&order=totalrank&duration=0&tids_1=0&page=' + str(i+1) # 共依次得到50页视频的网址
# print(link)
r = requests.get(link, headers=headers, timeout=10) #获取网页代码
#通过页响应状态码判断是否抓取正常
#print(r)
print(str(i + 1), "页 响 应 状 态 码:", r.status_code)
#美化抓取的网页代码方便解析
soup = BeautifulSoup(r.text, 'lxml')
#print(soup)
#抓取关键字段以备后续获取数据
uptimes = soup.find_all('span', class_='so-icon time') #上传时间
# print(time)
#print(time.get_text())
upnames = soup.find_all('a', class_='up-name') #up主
#for i in range(0, len(upnames)):
#print(upnames[i].get_text())
titles = soup.find_all('a', class_='title') #视频标题
#print(titles)
#for i in range(0, len(titles)):
# print(titles[i].get_text())
links = soup.find_all('a', class_='title') #视频链接
#for i in range(0, len(links)):
# print(links[i].get('href'))
#print(links.get('herf'))
watch_nums = soup.find_all('span', class_='so-icon watch-num') #播放量
#for i in range(0, 20):
# print(watch_nums[i].get_text())
subtitle_numbers = soup.find_all('span', class_='so-icon hide') #弹幕数
#numbers = range(1, 21)
#pages = range(1, 51)
evaluates = soup.find_all('div', class_='des hide') #简介
#引入时钟
#得到时间tim1和tim2。
#tim1作为数据更新时间显示在输出的Txt文件内,%Y %m %d %H %M %S分别表示年月日时分秒要注意这里的%H %M %S之间不能用:连接,用_连接即可。
#tim2用作文件命名,因为获取1000条数据有可能卡时间超过1分钟,所以为了避免输出多个文件,仅取到以时为单位命名即可
tim1 = time.strftime('%Y-%m-%d %H_%M_%S', time.localtime(time.time()))
tim2 = time.strftime('%Y-%m-%d %H', time.localtime(time.time()))
# 将信息放进字典中
for uptime, title, upname, link, watch_num, subtitle_number, evaluate in zip(uptimes, titles, upnames, links, watch_nums, subtitle_numbers, evaluates):
data = {
#'页数': page,
#'序号': number,
'视频名字': title.get_text(),
'up主': upname.get_text(),
'链接': link.get('href'),
'弹幕数': subtitle_number.get_text(),
'播放量': watch_num.get_text(),
'上传时间': uptime.get_text(),
'简介': evaluate.get_text()
}
print(data)
# 写入文件
fname = 'D:/web_homework_1/' + tim2 + r'result.txt'
file = open(fname, 'a', encoding="utf-8")
file.write('****************' + 'tip:以下视频数据更新时间为' + ' ' + tim1 + '**************************')
file.write('\n\n\n')
for k, v in data.items():
s2 = str(v)
file.write(k + ' ' + ':' + ' ')
file.write(s2 + ' ')
file.write('\n')
file.close
return 0
get_top()
'''
import time
tim = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
print(tim)
'''
运行结果:
txt文件: