首先需要学习以下基础知识
1.python基础
2.前端页面技术
3.爬虫技术
什么是互联网爬虫
通过一个程序根据URL进行爬取网页,获取有用信息。使用程序模拟浏览器,去想服务器发送请求,获取响应信息。
爬虫核心
抓取网页,解析数据,爬虫和反爬虫之间的博弈(难点)
爬虫的用途
数据分析/人工智能,社交软件冷启动,舆情监控,竞争对手监控
爬虫分类
通用爬虫:实例 百度、360、google等搜索软件
缺点:抓取的数据大多是无用的,不能根据用户的需求精准获取数据
聚集爬虫:功能:根据需求,实现爬虫程序,抓取需要的数据
设计思路:
1.确定需要,获取url,
2.模拟浏览器通过http协议访问url,获取服务器返回的html代码
3.解析html字符串(根据一定规则提取需要的数据)
反爬手段
1.User Agent(用户代理)简称UA,是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU类型,浏览器版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
2.代理IP 如果超出常人的基本操作基本行为,就会封掉IP
3.验证码访问 打码平台
4.动态加载网页 网站返回的是js数据,并不是网页的真实数据
5.数据加密 分析js代码
urllib库使用
urllib.request.urlopen()模拟浏览器向服务器发送请求
需求:#使用urllib获取百度首页的源码
第一步:定义一个URL(要访问的地址)
URL的组成部分:
在后面请求对象的定制中
url='http://www.baidu.com'
第二步:模拟浏览器向服务器发送请求
导入import urllib.request
response=urllib.request.urlopen(url) 当模拟浏览器向服务器发送请求时,服务器会给你一个反馈,需要一个变量接受这个反馈,常用响应response来接收这个反馈。
第三步:获取响应中的页面的源码(不要别的),获取到的内容用content接受
content=response.read()
read()方法:返回的是字节形式的二进制数据(带b),需要将二进制的数据转换成字符串,这个过程叫做解码,方法叫decode('编码的格式')
content=response.read().decode('utf-8')(utf-8对应页面的编码格式)
第四步:打印数据(直到获取的是否有内容)
print(content)
服务器返回的response中不仅仅有页面源码,除了read()获取源码外还有其他方法
一个类型和六个方法
print(type(response)) 获取到的类型为:HTTPResponse
response是HTTPResponse的类型
contend=response.read() 读取响应的内容,按照一个字节一个字节的去读
content=response.read(5) 返回了5个字节,代表返回多少个字节
content=response.readline() 只能读取一行,但是快
content =response.readlines() 一行一行的读,直到读完,还是一个二进制
print(response.getcode())返回状态码,判断代码是否有问题,如果返回200则代码逻辑没有错。
print(response.geturl()) 返回的是url地址
print(response.getheaders()) 返回的是响应头(状态信息)
将爬取的东西下载到本地(采集图片,视频等)
可以下载网页,图片,视频
url_page='http:www.baidu.com'
urllib.request.urlretrieve(url,filename)
参数url代表下载的路径,filename文件的名字
可以写url=url_page,'baidu.html' 注意文件后缀很重要
同理图片和视频下载类似
import urllib.request
#下载一个网页
url_page='http://www.baidu.com'
#url代表下载的路径 filename文件的名字
#在python中 可以写变量的名字 也可以直接写值
urllib.request.urlretrieve(url_page,'baidu.html')
#下载图片
url_img='https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi2.hdslb.com%2Fbfs%2Farchive%2Fbe8d5274c6f1c9957e1e5262f3b56e89854e1113.jpg&refer=http%3A%2F%2Fi2.hdslb.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1669605623&t=8a83fec7e865a1e087c4ac5355ae5e2a.jpg'
urllib.request.urlretrieve(url=url_img,filename='lisa.jpg')
#下载视频
url_video='https://vd2.bdstatic.com/mda-njtfkfkcwnvz04py/sc/cae_h264/1666960923439992738/mda-njtfkfkcwnvz04py.mp4?v_from_s=hkapp-haokan-nanjing&auth_key=1667015621-0-0-7fcec793e09a5b911662bb61552c6195&bcevod_channel=searchbox_feed&cd=0&pd=1&pt=3&logid=1421108170&vid=9049491074114251603&abtest=104959_2-104859_2-105227_2&klogid=1421108170'
urllib.request.urlretrieve(url_video,filename='children.mp4')
urllib请求对象的定制
url='https://www.baidu.com'
url的组成有6部分
http/https(协议)加s的更加安全,www.baidu.com域名也就是主机地址 ,
端口号:http的是80,https的是443,mysql的是3306, oracle 的是1521 , redis是6379
https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6 路径:s 参数:?后面的数据 wd=周杰伦 锚点:#
返回的数据不完整,遇到的第一个反爬是因为给的数据不完整,
网页检查,点击网络network,在标头headers里 获取UA,发现有冒号像字典类型的数据,字典里要有字符串。
源码中显示urlopen的参数并提示
#Open the URL url, which can be either a string or a Request object
这时就需要请求对象的定制:因为urlopen方法中不能存储字典,所以headers不能传入。
伪装成一个整体,因为参数顺序的问题不能直接写url,headers,
需要关键字传参:
request=urllib.request.Request(url=url,headers=headers) response= urllib.request.urlopen(request)
编解码
1.get请求方式:urllib.parse.quote()
需求 获取https://www.baidu.com/s?wd=周杰伦
url ='https://www.baidu.com/s?wd='
#要将周杰伦三个字编成unicode编码的格式
#需要依赖于urllib.parse使用quote方法
name = urllib.parse.quote('周杰伦')
url=url+name
#编码集的演变
#需求 获取https://www.baidu.com/s?wd=周杰伦的网页源码
import urllib.request
import urllib.parse
url ='https://www.baidu.com/s?wd='
#请求对象定制--为了解决反爬的第一种手段UA
headers = {
'User-Agent':' '
}
#要将周杰伦三个字编成unicode编码的格式
#需要依赖于urllib.parse使用quote方法
name = urllib.parse.quote('周杰伦')
#print(name)#%E5%91%A8%E6%9D%B0%E4%BC%A6
url=url+name
#print(url)#https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6
#请求对象的定制
request=urllib.request.Request(url=url,headers=headers)
#模拟浏览器向服务器发送请求
response= urllib.request.urlopen(request)
#获取响应的内容
content=response.read().decode('utf-8')
#打印数据
print(content)
2.get请求方式:urlencode方法(应用场景就是多个参数时使用)
wd后面用&符号连接了很多参数,需要转为unicode字符,要求参数要以字典的形式存在。
#urlencode应用场景,多个参数的时候使用
#https://www.baidu.com/s?wd=周杰伦&sex=男
'''
import urllib.parse
data ={
'wd':'周杰伦',
'sex':'男',
'location':'中国台湾省',
}
a=urllib.parse.urlencode(data)
#print(a)#wd=%E5%91%A8%E6%9D%B0%E4%BC%A6&sex=%E7%94%B7
#wd=%E5%91%A8%E6%9D%B0%E4%BC%A6&sex=%E7%94%B7&location=%E4%B8%AD%E5%9B%BD%E5%8F%B0%E6%B9%BE%E7%9C%81
'''
#获取https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6&sex=%E7%94%B7的网页源码
import urllib.request
import urllib.parse
base_url='https://www.baidu.com/s?'
data={
'wd':'周杰伦',
'sex':'男',
'location':'中国台湾省',
}
new_data=urllib.parse.urlencode(data)
#请求的资源路径
url=base_url+new_data
#防止做反爬
headers={
'User-Agent': ''
}
#请求对象的定制
request=urllib.request.Request(url=url,headers=headers)
#模拟浏览器向服务器发请求
response=urllib.request.urlopen(request)
#获取网页源码的数据
content=response.read().decode('utf-8')
#打印数据
print(content)
3.post请求方式:
#post请求的参数 必须要进行编码 编码后必须调用encode方法
data=urllib.parse.urlencode(data).encode('utf-8')
#post的请求参数是不会拼接在url后面,而是需要放在请求对象定制的参数中
#post请求的数据必须进行编码
request=urllib.request.Request(url=url,data=data,headers=headers)
#post请求百度翻译
#post请求
import urllib.request
import urllib.parse
url ='https://fanyi.baidu.com/sug'
headers = {
'User-Agent':''
}
#post请求的参数应该放在哪
data={
'kw':'spider',
}
#post请求的参数 必须要进行编码 编码后必须调用encode方法
data=urllib.parse.urlencode(data).encode('utf-8')
#post的请求参数是不会拼接在url后面,而是需要放在请求对象定制的参数中
#post请求的数据必须进行编码
request=urllib.request.Request(url=url,data=data,headers=headers)
#模拟浏览器向服务器发送请求
response=urllib.request.urlopen(request)
#获取响应的数据
#print(response)#TypeError: POST data should be bytes
content=response.read().decode('utf-8')
#字符串变成json对象
import json
obj=json.loads(content)
print(obj)
#post请求方式的参数必须 编码 data=urllib.parse.urlencode(data)
#编码之后必须调用encode方法 data=urllib.parse.urlencode(data).encode('utf-8')
#参数是放在请求对象定制的方法中 request=urllib.request.Request(url=url,data=data,headers=headers)
百度翻译 -详细翻译
import urllib.request
import urllib.parse
url='https://fanyi.baidu.com/v2transapi?from=en&to=zh'
#起决定性作用的是cookie,
headers = {
#'Accept': '*/*',
#'Accept-Encoding':' gzip, deflate, br', #需要注释掉
#'Accept-Language': 'zh-CN,zh;q=0.9',
#'Acs-Token': '1666940606973_1667025165241_wUz+zBfO7j24XvsZbTcRsnibLDg7sS3ASv0TjBc7Wa49hvH49OwhCxx2Ha7pZC8HQEAvi7Z6DR3j2nzOu9VKvktKFfiRa3n971UsV/WrSK11dyeLQbxOkvhPYad7NEd8JDbz/YL4+y97jKIeJieLplG71EK2uZKOgmkWkdp9456MUtoX3136SsoJCCWFTSLnMsAJUrLu4XpFHJWbzS8uq7GsHp3p/2L4wahCAM9s+rmr+lOg8hXhPzmWBA37DT81iPygwWe8/O/j66zF+730Ej+nGEH3bkThwRN6XzVetuMgpzpKgVgur+7A+TihqGNs',
#'Connection':'keep-alive',
#'Content-Length': '135',
#'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie':' BIDUPSID=9111318699517B1BF24BF48B93814A82; PSTM=1623657042; BAIDUID=217613BFEA4B7E9B42ADC0795B1C33DD:FG=1; H_PS_PSSID=26350; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; BAIDUID_BFESS=217613BFEA4B7E9B42ADC0795B1C33DD:FG=1; BA_HECTOR=a10g202hag808h0ha50g1u4i1hlpdbj1b; ZFY=k9XM400WDOObh0TZMyuxNIG2qgk9ngEvUv:BPQXMOMb8:C; BDRCVFR[u-uf9TAkSn6]=mk3SLVN4HKm; delPer=0; PSINO=6; BCLID=8273724148951262294; BCLID_BFESS=8273724148951262294; BDSFRCVID=JBKOJexroG0uo4JjVBHvhB41J_weG7bTDYrEDb8tOfSVLYPVJeC6EG0Pts1-dEu-EHtdogKKy2OTH9DF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; BDSFRCVID_BFESS=JBKOJexroG0uo4JjVBHvhB41J_weG7bTDYrEDb8tOfSVLYPVJeC6EG0Pts1-dEu-EHtdogKKy2OTH9DF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; H_BDCLCKID_SF=tR3h3RrX26rDHJTg5DTjhPrMy45iWMT-MTryKKJaaKbkjxQtybjsL63LyRnfKx-fKHnRh4oN3n_Wfh7I0pjdWq8ZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPU2H59LUk83gcdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLK-oj-D_9jTrP; H_BDCLCKID_SF_BFESS=tR3h3RrX26rDHJTg5DTjhPrMy45iWMT-MTryKKJaaKbkjxQtybjsL63LyRnfKx-fKHnRh4oN3n_Wfh7I0pjdWq8ZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPU2H59LUk83gcdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLK-oj-D_9jTrP; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1667022862; APPGUIDE_10_0_2=1; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; ab_sr=1.0.1_YWQ3OTY4ODIwNGFjNDA3YjM3NGY0NGE4ZGQwY2RkZTU2NDdjNGVkMTVhMzVjNjdmMDA3YThmN2FhZDM1YmI3M2VlOGY1ZWY5NzdkMGQ3ZDU1MzM3YWM0MzVmOGU1NWMyODcwZDE3NGY2ZmM2NTE2MmRhMmMxNGZiNDJkMDM2MDJhY2E1OWZhYWU4NzcwZWExNDliMGJkNzBkMjc0ODUyNA==; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1667025112',
#'Host': 'fanyi.baidu.com',
#'Origin':' https://fanyi.baidu.com',
#'Referer': 'https://fanyi.baidu.com/',
#'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"',
#'sec-ch-ua-mobile': '?0',
#'sec-ch-ua-platform': '"Windows"',
#'Sec-Fetch-Dest': 'empty',
#'Sec-Fetch-Mode': 'cors',
#'Sec-Fetch-Site': 'same-origin',
#'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
#'X-Requested-With': 'XMLHttpRequest}',
}
data={
'from':'en',
'to':'zh',
'query':'love',
'transtype':'realtime',
'simple_means_flag':'3',
'sign':'198772.518981',
'token':'65b3e51de584d7a01742ac55c9f6d303',
'domain':'common',
}
#post请求的参数 必须进行编码 并且要永encode方法
data=urllib.parse.urlencode(data).encode('utf-8')
#请求对象的定制
request=urllib.request.Request(url=url,data=data,headers=headers)
#模拟浏览器向服务器发送请求
response=urllib.request.urlopen(request)
#获取响应的数据
content=response.read().decode('utf-8')
import json
obj = json.loads(content)
print(obj)
ajax的get请求豆瓣电影 ,找数据的标头
#(3)数据下载到本地
#open方法默认情况使用的是gbk的编码 无果我们需要保存汉字 那么需要在open方式中指定编码格式utf_8
#encoding='utf-8'
fp=open('douban.json','w',encoding='utf-8')
fp.write(content)
另一种形式(快捷键ctrl+shift+l显示json不是一行)
#with open('douban1.json','w',encoding='utf-8')as fp:
# fp.write(content)
#get请求
#获取豆瓣电影的第一页数据并且保存起来
import urllib.request
url='https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=0&limit=20'
headers = {
'User-Agent':''
}
#(1)请求对象的定制
request=urllib.request.Request(url=url,headers=headers)
#(2)获取响应的数据
response = urllib.request.urlopen(request)
content=response.read().decode('utf-8')
print(content)
#(3)数据下载到本地
#open方法默认情况使用的是gbk的编码 无果我们需要保存汉字 那么需要在open方式中指定编码格式utf_8
#encoding='utf-8'
fp=open('douban.json','w',encoding='utf-8')
fp.write(content)
#with open('douban1.json','w',encoding='utf-8')as fp:
# fp.write(content)
获取豆瓣电影前10页排名,在于接口的寻找
#豆瓣电影前10页数据
#https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=0&limit=20
#https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=20&limit=20
#https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=40&limit=20
#https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=60&limit=20
#https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=80&limit=20
#https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=100&limit=20
#page 1 2 3 4 5
#start 0 20 40 60 80
#start (page-1)*20
#下载豆瓣电影前1页的数据
#(1)请求对象的定制
#(2)获取响应的数据
#(3)下载数据
import urllib.parse
import urllib.request
def create_request(page):
#基础的url
base_url='https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&'
data={
'start':(page-1)*20,
'limit':20
}
data=urllib.parse.urlencode(data)
url=base_url+data
print(url)
headers={
'User-Agent': ' '
}
request = urllib.request.Request(url=url,headers=headers)
return request
def get_content(request):
response=urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
def down_load(page,content):
with open('douban_'+str(page)+'.json','w',encoding='utf-8') as fp:
fp.write(content)
#程序入口
if __name__=='__main__':
start_page=int(input('请输入起始页码'))
end_page=int(input('请输入结束的页面'))
for page in range(start_page,end_page+1):
# 每一页都有自己的请求对象的定制
request = create_request(page)
#获取响应的数据
content=get_content(request)
#下载
down_load(page,content)