浏览器到网站服务器响应
爬虫就是用代码替代里浏览器,并对返回的信息进行解析
爬虫的应用
12306抢票、黄牛抢特价机票、搜索引擎、微博买赞刷评论、微博抢红包、通过网络机器人提高搜索引擎排名、比价网、获取其他平台点评
伪装UA
UA(User-Agent)在信息头中用于对请求的身份进行识别,某些网站为防止崩溃,会对机器人进行限制。比如发现是个python请求就直接拒绝了。
step1)获取浏览器UA
任意网页右键》》审查元素》》Network》》刷新/保存等任意操作》》Name中选中后任意请求》》Headers 'Request Headers'user-agent
step2)使用字典设置headers
import requests
url2='http://httpbin.org/get'
header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
data=requests.get(url2,headers=header)
print(data.text)
使用检查元素寻找网页和代码的对应关系
审查元素》》Elements》》点击左上角指针可定位网页到代码/不选中指针鼠标在代码上下移动可定位代码到网页
爬取豆瓣新书速递内容
step1)requests发送请求,返回test信息
step2)处理为一个BeautifulSoup对象,便于解析
step3)利用审查元素寻找代码和网页的对应关系
step4)利用find 和find_all方法提取信息块
step5) 解析信息块中的内容
step6)存储解析后的数据
简单来说就是:获取——解析——存储 三步
import requests
from bs4 import BeautifulSoup
#返回网页信息
url='https://book.douban.com/latest'
header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
data=requests.get(url,headers=header)
# print(data.text)
#处理为一个便于解析的BeautifulSoup对象
soup=BeautifulSoup(data.text,'lxml')
# print(soup)
#获得信息块
books_left=soup.find('ul',{'class':'cover-col-4 clearfix'})
books_left=books_left.find_all('li')
books_right=soup.find('ul',{'class':'cover-col-4 pl20 clearfix'})
books_right=books_right.find_all('li')
books=list(books_left)+list(books_right)#这里是否使用list对最终结果无影响
# print(len(books))
#对信息块中的每个元素进行解析
img_urls=[]
stars=[]
for book in books:
#获取图片的地址
info=book.find('a')#这里使用find还是find_all会对后面的代码有影响
info=info.find('img').get('src')
img_urls.append(info)
# 获取星级
info2=book.find('p',{'class':'rating'}).get_text()#返回去除html标签后的纯文本
score=info2.replace('\n','').replace(' ','')
stars.append(score)
print(stars)
解析信息块常用方法
find#返回第一个带有指定内容的块,注意=相当于python中的字典
find_all#返回所有带有指定内容的块,是一个list
get(key)#获取key对应的信息
get_text()#获取去除带<>的html标签后的纯文本
replace#替换一些内容或去除换行‘\n’或空格' '
使用try处理报错信息
有时候一些网站的url会因为更新啊之类的问题而报错,代码需要对这些error有处理能力,不要一出错就停止运行了,那之前处理的都白费了。善用try... except ...
import requests
url='http://news.baidu.com/'
header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
try:
data=requests.get(url,headers=header)
except requests.exceptions.ConnectionError as error:#可带多个except,不指明错误类型时,默认所有错误
print('info :',error)
else:#在所有except之后,可带一个else,未出现异常时执行
print(data.text)
finally:#任何情况都会执行,一般用于释放文件或网络等资源
print('end------')
服务器状态码5XX
使用requests.get(url)获得的data,不仅有data.text文本信息,还有data.status_code状态码信息,data.content,对数据范围进行判断,若在500~600之间(if (data!=None) and (500<=data.status_code<600):),可以先暂停(time.sleep(1))后刷新请求(递归)。这个过程可以执行几次(if num <3:)
请求超时
谷歌等网站由于不能打开,请求时会一直卡在请求这一步,可设置timeout时间控制请求超时
data=requests.get(url,timeout=5)
爬虫声明、限制robots.txt
例如百度的声明网址是https://www.baidu.com/robots.txt
打开该网址后第一个是:
User-agent: Baiduspider
Disallow: /baidu
Disallow: /s?
Disallow: /ulink?
Disallow: /link?
Disallow: /home/news/data/
意思是说,UA为Baiduspider时,不能访问http://www.baidu.com/baidu等网址,其他没有注明Disallow的则可以访问。
下面有个代码示范了使用urllib库对robots.txt的解析
import urllib.robotparser
rp=urllib.robotparser.RobotFileParser()
rp.set_url('http://www.baidu.com/robots.txt')
rp.read()
a=rp.can_fetch('Baiduspider','http://www.baidu.com/baidu')
print(a)
b=rp.can_fetch('Baiduspider','http://www.baidu.com/cpro')
print(b)
set_url为robots.txt文件的网址,can_fetch两个参数分别为UA和要检验的网址,返回值为布尔值,a=False,b=True
可通过robots.txt检验当前UA能否访问的url。
动态UA
简单来说,就是有个库可以获得众多浏览器的UA,不需要自己对各个浏览器来一下【审查元素】操作。
from fake_useragent import UserAgent
ua=UserAgent()
print(ua.ie)
print(ua.random)
代理ip
import requests
proxies_dict={'http':'IP:端口','https':'IP:端口'}
data=requests.get(url,proxies=proxies_dict)
乱码编码
先检验编码,后设置编码。这里charset返回的信息是【{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}】表明:编码方式为ASCII编码的可能性是100%
import requests
import chardet
data=requests.get('http://baidu.com')
print(data.text)
print('********************')
charset=chardet.detect(data.content)
print(charset)
data.encoding=charset['encoding']
print(data.text)
正则表达式
形式为re.findall、match、find、search(正则表达式,待检验字符串)
() | 表明要提取的就是括号里的内容 |
r'xxxxxx' | 不把引号中的\视为转义符 |
. | 除换行符以外的任意字符 |
* | 包括0个的任意个字符 |
{2} | 同时出现两次前面的字符 |
? | 非贪婪匹配模式,即匹配尽可能短的字符串 |
\w | 大小写字母,数字,下划线 |
herf | 链接,比如r'herf="(http.*?)"' |
模拟登录、验证码
使用cookie的验证用户的验证状态,cookie的手动获取可通过右键审查元素的方法。自动的方法需要提交表单登录,然后获取保存cookie
验证码一般通过:手动输入,图像转字符技术,云打码平台(将验证码、点击下图中的XX等在线反给标注人员,并记录选中图像实际标签)。
存储图片
# 方法一
import requests
img_data=requests.get(img_url).content#二进制内容
with open (str(img_title)+'.jpg','wb') as f:
f.write(img_data)
# 方法二
import urllib.request as req
link = 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=4233772603,2493444113&fm=26&gp=0.jpg'
req.urlretrieve(link, './1.jpg')
修正由于编码问题导致的中文乱码问题
使用ftfy库的fix_text方法
import requests
from ftfy import fix_text
data=requests.get('http://www.baidu.com')
print(data.text)
print(fix_text(data.text))
带页码翻页
以北京市医疗保障局为例:
http://ybj.beijing.gov.cn/2020_zwfw/2020_bmcx/202002/t20200217_1644107.html
翻页方式如下图:
在网页右击->选择检查->打开Network信息-》点击其他页面翻页-》看list里的headers信息
Referer是实际要爬的url,右下方 form data提交了页面的page信息。
对这种需要提交页码的网页,爬虫请求时,提交page信息,脚本如下:
import requests
from bs4 import BeautifulSoup
url = 'https://fw.ybj.beijing.gov.cn/ddyy/ddyy/list'
for page in range(2): # 爬前2页
pagedata = {"page":(None, str(page+1))}
data = requests.get(url, params=pagedata)
soup = BeautifulSoup(data.text, 'lxml')
自动翻页
不需要翻页,下拉自动加载更多图片的,推测为ajax请求,可用百度图库感受一下
在网页右击->选择检查->打开Network信息-》下拉翻页-》点击XHR-》查看headers信息里的Request url-》查看response信息
对response进行json在线解析,可知‘thumbURL’包含了图像url信息。
request url信息为
https://image.baidu.com/search/acjson?tn=resultjson_com&logid=11441412425879201126&ipn=rj&ct=201326592&is=&fp=result&queryWord=python&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=&z=&ic=&hd=&latest=©right=&word=python&s=&se=&tab=&width=&height=&face=&istype=&qc=&nc=1&fr=&expermode=&force=&pn=90&rn=30&gsm=5a&1614001042128=
其中‘pn=90&rn=30’表示每次请求30个数据(最大可设置为60),从第90个开始显示,有点查数据库limit pn,pn+rn 的意思。word是我查询的词汇,将这些信息放在request的参数里。https://image.baidu.com/search/acjson是实际请求request的url
import requests
word = 'python编程'
page_img_n = 60 # 设置一页69个图像
url = 'https://image.baidu.com/search/acjson'
header = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
for page in range(1, 3): #爬第一页到第三页
data = {'word': word, 'pn': page * page_img_n, 'rn' : page_img_n, 'tn' : 'resultjson_com', 'ipn' : 'rj'}
ret = requests.get(url, headers=header, params=data)
print(ret)
print(ret.url)
print(ret.content.decode())
还有一种简单一点的方法,不用把参数都写成字典的形式,直接把request url抄下来,改一下参数。以必应为例:
Request URL:
https://cn.bing.com/images/async?q=python%e7%bc%96%e7%a8%8b&first=101&count=35&relp=35&tsc=ImageBasicHover&datsrc=I&layout=RowBased&mmasync=1&dgState=x*366_y*1161_h*184_c*2_i*71_r*15&IG=C502AAA6EEEF494F87DA1B21193FD0DE&SFX=3&iid=images.5533
import urllib
from bs4 import BeautifulSoup
word = 'python编程'
page_img_n = 60 # 设置一页69个图像
url = 'https://cn.bing.com/images/async?q={}&first={}&count=35&relp=35&tsc=ImageBasicHover&datsrc=I&layout=RowBased&mmasync=1&dgState=x*366_y*1161_h*184_c*2_i*71_r*15&IG=C502AAA6EEEF494F87DA1B21193FD0DE&SFX=3&iid=images.5533'
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
for page in range(1, 2): # 爬第一页到第三页
# UTF-8编码
InputData = urllib.parse.quote(word)
ret = urllib.request.Request(url.format(InputData, str(page*35)), headers=header) # 从page*35开始的35张
res = urllib.request.urlopen(ret)
soup = BeautifulSoup(res.read(), 'html.parser')
# BeautifulSoup的对象可查看特定class的信息
for item in soup.select('.iusc'):
# 通过类属性查看url
link = eval(item.attrs['m'])['murl']
print(link)
---------------------------------------------------------------------------------------
常见报错处理:
- Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?
缺少html解析器
pip install lxml
- 不信任的镜像源
不用镜像或者改pip配置文件
pip install bs4
- csv中中文信息乱码
CSV是用UTF-8编码的,而EXCEL是ANSI编码,若想使保存的csv文件用excel打开时可以正常显示中文,则:
1)在保存文件时设置编码方式 encoding=‘ANSI’
result.to_csv('douban.csv',index=None,encoding='ANSI')
2)或者用记事本打开,另存为时选择ANSI编码方法
参考代码:
https://github.com/shenxiangzhuang/PythonDataAnalysis