python3 实现爬虫 urllib篇 + 数据处理(采用bs4)
爬虫需要你至少知道html标签和css的超基本的知识,建议先学了再学爬虫
很简单的,只要一天你就能明白html css分别是做什么的了。
不想学就只好边看我说明边自己百度不懂的地方了
完整代码见最后一个代码块,不建议直接拿去用,建议慢慢看懂原理写出你自己独特的代码。
先仍几个参考文档
urllib文档:https://docs.python.org/3.5/library/urllib.html
beautifulsoup中文文档:https://beautifulsoup.readthedocs.io/zh_CN/latest/
re文档:https://docs.python.org/3/library/re.html
1.获取文本信息
urllib是python3下载完自带的包
bs4需要下载
配置好环境变量后cmd中输入pip install bs4
from urllib import request
from bs4 import BeautifulSoup
#要抓取的链接
url = "https://blog.****.net/qq_36376711/article/details/86614578"
#获取到的内容
content = request.urlopen(url)
#获取网页的源码
encode_html = content.read()
#print(encode_html)#打印出来会发现是编码过的html
#解码,一般是utf-8。此处仅举例,后续说明如何选择恰当的编码格式
html = encode_html.decode("utf-8")
#print(html)#打印发现中文正常显示了
最简单的访问就完成了
下面对获取到的数据进行解析
此处以获取该文章阅读数为例
按下F12/或者右键->审查元素。耐心找到该对象的class的值
发现阅读数对应的class是 read-count,位于span标签对内
#应用BeautifulSoup对获取到的数据进行格式转换,方便数据处理
soup = BeautifulSoup(html,"html.parser")
#同样方法找到文章标题的字体大小标签,发现是h1(不懂class,h1,标签对是啥的自己先百度html标签看了
#再来)
#一看就知道这个大小的字体只有标题
print("文章:",soup.h1)#直接通过标签属性访问
#find_all是获取所有标签对
print("阅读数:",soup.find_all("span","read-count"))#通过标签加类别
打印结果发现
我们不想看到的标签对部分也被打印出来了
于是修改上述部分代码为:
print("文章:",soup.h1.get_text())
#因为count是个列表,所以不能像上面一样直接get_text()
for c in count:
print("阅读数:",c.get_text())
这种写法在文章被删除,****服务器宕机等情况下都无法正常访问,
单看这个程序你不觉得是个大问题,但是,当你是在多个网址爬取信息,
并汇总处理时,或者通过改变url循环访问不同网址时
我们不希望因为一个网址的问题导致整个程序终止
在高频率访问时,因为没有设置访问间隔,会被反爬虫机制识别出来。
并且,有些网站需要验证码,有的网站需要登陆,有的网站需要headers信息
才能正常访问。海外链接需要*也可能导致意外中止。
你也需要把获得的数据不仅仅是输出到控制台,你也许想输出到txt或者csv文件中
上述代码还可以写成
soup.find_all(“span”,{“class”:“read-count”})
find_all还可以写成findAll,find_all更符合python语法习惯
获取文字类比上面即可,不再赘述,没学会95%是因为你html知识的问题
大多数人是因为不会分析html页面才不知道自己该怎么取得想要的信息
而不是python知识的问题
2.获取图片
延续上面的代码添加内容
$是正则表达式,可以参见我的另一篇文章,也可以你自行搜索
https://blog.****.net/qq_36376711/article/details/86505332
import re#一个字符串处理的包
#获取图片的链接,"img表示选取所有img标签对"".jpg$表示获取标签对中
#所有以.jpg结尾的内容"
links = soup.find_all('img',"",src=re.compile(r'.jpg$'))
#打印出所有链接中src属性的内容
print(links.attsr["src"])
接下来讲如何获取图片
import time#时间相关的包
# 设置保存图片的路径,否则会保存到程序当前路径
#要求path必须存在,所以测试时发现bug多半是因为你没有创建该文件夹
#修改path的值或者自己去E盘创建该文件夹,那些不阅读代码光复制粘贴运行的估计会认为
#我的教学有问题
path = r'E:\pystest\images'
#路径前的r是保持字符串原始值的意思,就是说不对其中的符号进行转义
for link in links:
#打印出所有链接中src属性的内容
print("正在下载:",link.attrs['src'])
#保存链接并命名,time.time()返回当前时间戳防止命名冲突
request.urlretrieve(link.attrs['src'],path+'\%s.jpg' % time.time())
#使用request.urlretrieve直接将所有远程链接数据下载到本地
结果:
3.完整代码
完善代码并增加稳定性
from urllib import request
from bs4 import BeautifulSoup
import re
import time
#导入chardet 用于检测编码
import chardet
def get_html_content(url):
try:
'''
urlopen 返回对象可以使用
1.geturl:返回请求对象的url
2.info:对象的meta信息,包含http返回的头信息
3.getcode:返回的http code
例如print("URL:{0}".format(page.getcode()))
'''
xhtml = request.urlopen(url).read()
#将bytes内容解码,转换为字符串
#html源码里面一般有编码格式,但是可能不准确,因为是其他人写的
#利用chardet检测编码
charset = chardet.detect(xhtml)
except Exception as e:
print(e)
#urlopen可能出现httperror,如404等
return None
try:
#如果找到encoding,返回其值,设置没有找到时默认为utf-8
#使用get取值防止出错
html = xhtml.decode(charset.get("encoding","utf-8"))
pass
except AttributeError as e:
print(e)
return None
soup = BeautifulSoup(html,"html.parser")
if soup is None:
return None
return soup
url = "https://blog.****.net/qq_36376711/article/details/85712738"
soup = get_html_content(url)
#如果获得的内容为空则直接退出
if soup is None:
exit(0)
print("文章:",soup.h1.get_text())
count = soup.find_all("span","read-count")
for c in count:
print("阅读量:",c.get_text())
links = soup.find_all('img',"",src=re.compile(r'.jpg$'))
path = r'E:\pystest\images'
print("以下图片将存储在:",path)
for link in links:
print("正在下载:",link.attrs['src'])
#建一个空的readme防止路径不存在错误
#直接创建文件夹更好,参考下面文章,为了代码简短所以我没用
#https://www.cnblogs.com/monsteryang/p/6574550.html
with open(r"E:\pystest\images\readme.txt","w") as file:
#pass表什么都不做
pass
request.urlretrieve(link.attrs['src'],path+'\%s.jpg' % time.time())
关于如何通过循环采集不同网页信息和应付反爬,验证码,利用scarpy或requests库爬虫等。以后有空我会另外写文章再在此补充链接,或者找较好教程的链接。
本博客为原创,根据作者在网易云课堂,实验楼和《python网络数据采集》一书中所学知识综合所写。
随说是原创,但你可以随意修改和发布此博文,甚至你可以说是你自己写的。