2020-07-16
2020-07-17 本文已影响0人
杜宇_8141
爬虫学习一
我的系统环境是ubuntu20.04,使用python3.8。
1.了解网页结构
-
打开chrome浏览器,按F12进入开发者模式,点击左上角箭头,再点击网页内容会找到源代码对应位置。
-
点击Network,会看到浏览器向服务器发出的请求时间图,点击图中最左边,再点击Headers,General包含url、远程服务器ip地址等信息,Response Headers是对服务器响应的格式约束,Request Headers包含了我们的浏览器信息。点击Response,看到服务器返回的信息。
2.爬虫框架
2.1整体框架
以爬取豆瓣top250影片信息为例
# -*- coding:utf-8 -*-
import urllib.request as ur
from bs4 import BeautifulSoup#网页解析获取数据
import re#正则表达式,进行文字匹配
import urllib.request,urllib.error#制定URL,获取数据
import xlwt#用于保存成excel
import sqlite3#进行SQLite数据库操作
def main() :
baseurl = "https://movie.douban.com/top250?start="
datalist = getData(baseurl)
savepath = "./Top250.xls"
saveData(datalist,savepath)
findLink = re.compile(r'<a href="(.*?)">')
#影片图片的规则
findImgSrc = re.compile(r'<img.*src="(.*?)"',re.S)#re.S让换行符包含在字符中
#影片片名
findTitle = re.compile(r'<span class="title">(.*)</span>')
#影片评分
findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>')
#评价人数
findJudge = re.compile(r'<span>(\d*)人评价</span>')
#找到概况
findInq = re.compile(r'<span class="inq">(.*)</span>')
#找到影片的相关内容
findBd = re.compile(r'<p class="">(.*?)</p>',re.S)
def getData(baseurl) :
datalist = []
for i in range(0,10) :
url = baseurl + str(i*25)
html = askURL(url)
soup = BeautifulSoup(html,"html.parser")
for item in soup.find_all('div',class_='item') :
data = []
item = str(item)
link = re.findall(findLink,item)[0]
data.append(link)
imgSrc = re.findall(findImgSrc,item)[0]
data.append(imgSrc)
titles = re.findall(findTitle,item)
if (len(titles) == 2) :
ctitle = titles[0]
data.append(ctitle)
otitle = titles[1].replace('/','')
data.append(otitle)
else :
data.append(titles[0])
data.append(' ')
rating = re.findall(findRating,item)[0]
data.append(rating)
judgeNum = re.findall(findJudge,item)[0]
data.append(judgeNum)
inq = re.findall(findInq,item)
if len(inq) != 0 :
inq = inq[0].replace("。",'')
data.append(inq)
else :
data.append(" ")
bd = re.findall(findBd,item)[0]
bd = re.sub('<br(\s+)?'," ",bd)
bd = re.sub('/'," ",bd)
data.append(bd.strip())
datalist.append(data)
print(len(datalist))
return datalist
def askURL(url) :
headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"}#构建一个header,防止被发现是爬虫,User-Agent不要出现空格
request = ur.Request(url=url,headers=headers)#构建一个请求
response = ur.urlopen(request)#发送请求
try :
response = ur.urlopen(request)
html = response.read().decode("utf-8")
# print(html)
return html
except urllib.error.URLError as e :
if hasattr(e,"code") :
print(e.code)
if hasattr(e,'reason') :
print(e.reason)
def saveData(datalist,savepath) :
book = xlwt.Workbook(encoding = "utf-8",style_compression=0) #创建workbook对象
sheet = book.add_sheet('doubanTop250',cell_overwrite_ok=True)#创建工作表
col = ('电影详情链接','图片链接','影片中文名','影片外文名','评分','评价数','概况','相关信息')
for i in range(0,8) :
sheet.write(0,i,col[i])
for i in range(0,250) :
print("第%d条"%(i+1))
data = datalist[i]
for j in range(0,8) :
sheet.write(i+1,j,data[j])
book.save(savepath)
#影片详情链接的规则
if __name__ == "__main__" :
main()
2.2抓取网页源代码
有的写法是import urllib,然后urllib.request.Request,但是这样会显示urllib没有request模块,应该是由于python版本的问题。User-Agent在浏览器的Request Headers中可以找到。
def askURL(url) :
headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"}#构建一个header,防止被发现是爬虫,User-Agent不要出现空格
request = ur.Request(url=url,headers=headers)#构建一个请求
response = ur.urlopen(request)#发送请求
try :
response = ur.urlopen(request)
html = response.read().decode("utf-8")
print(html)
return html
except urllib.error.URLError as e :
if hasattr(e,"code") :
print(e.code)
if hasattr(e,'reason') :
print(e.reason)
给askURL函数传入百度首页的URL:https://www.baidu.com,就会打印出百度首页的源代码,内容较多,这里就不展示了。注意,如果返回错误信息418,则说明对方服务器识别出爬虫。
将打印内容保存到baidu.html中,用chrome浏览器打开,会发现正是百度首页的界面
2.3网页解析
对于一个保存好的网页baidu.html,我们可以通过BeautifulSoup来进行解析
from bs4 import BeautifulSoup
file = open("./baidu.html","rb")
html = file.read()
bs = BeautifulSoup(html,"html.parser")
#print(bs.title)
#print(bs.a)
#print(bs.head)
#查找含标签"a"的分区
t_list = bs.find_all("a")
print(t_list)
#函数法
def name_is_exists(tag) :
return tag.has_attr("name")
t_list = bs.find_all(name_is_exists)
print(t_list)
#Kwargs参数,注意class_有下划线
#t_list = bs.find_all(id = "head")
t_list = bs.find_all(class_=True)
for item in t_list :
print(item)
#text参数
t_list = bs.find_all(text = "hao123")
t_list = bs.find_all(text = ["hao123","地图",“贴吧”])
for item in t_list :
print(item)
#limit参数,限制最多查找个数
t_list = bs.find_all("a",limit=3)
for item in t_list :
print(item)
#CSS选择器
#t_list = bs.select('title') #通过标签来查找
#t_list = bs.select(".mnav") #通过类名来查找
#t_list = bs.select("#v1")#通过id来查找
#t_list = bs.select("a[class='bri'])#通过属性查找
#t_list = bs.select("head > title")#通过子标签
t_list = bs.select(".mnav ~ .bri")#通过兄弟标签
print(t_list[0].get_text())
2.4正则表达式提取信息
正则表达式能够精确提取信息,这里直接搬运一下常用操作符
常用操作符1 常用操作符2
举例,如何匹配aabbcc@126.com,可以用.*@126.com
Re库主要功能函数
修饰符
举例
import re
#创建模式对象
pat = re.compile("AA")
m = pat.search("ABCAADDCCAAA")
print(m)#默认返回第一个匹配到的位置
#输出结果<re.Match object; span=(3, 5), match='AA'>
#无模式对象匹配
#m = re.search("asd","Aasd")
#print(m)
print(re.findall("a","ASDaDFGAa"))
print(re.findall("[A-Z]+","ASDaDFGAa"))
#替换方法sub
print re.sub("a","A","abcdcasd"))
#找到所有'a',并将其替换为'A'
建议在正则表达式中,被比较的字符串前面加上r,如 r"\aabd-'",不用担心转义字符的问题。
2.5保存数据
def saveData(datalist,savepath) :
book = xlwt.Workbook(encoding = "utf-8",style_compression=0) #创建workbook对象
sheet = book.add_sheet('doubanTop250',cell_overwrite_ok=True)#创建工作表
col = ('电影详情链接','图片链接','影片中文名','影片外文名','评分','评价数','概况','相关信息')
for i in range(0,8) :
sheet.write(0,i,col[i])
for i in range(0,250) :
print("第%d条"%(i+1))
data = datalist[i]
for j in range(0,8) :
sheet.write(i+1,j,data[j])
book.save(savepath)
最终得到这样一张excel表
保存结果
3.补充
3.1 get和post方法的区别
get请求:
一般情况下,只从服务器获取数据,并不会对服务器数据产生影响的时候用get请求;
如 :
response = urllib.request.urlopen("http://httpbin.org/get")
print(response.read().decode("utf-8"))
post请求:
向服务器发送数据(登录),上传文件等,会对服务器资源产生影响的时候用post请求
import urllib.parse
data = bytes(urllib.parse.urlencode({"hello":"world"}),encoding="utf-8")
response = urllib.request.urlopen("http://httpbin.org/post",data=data)
print(response.read().decode("utf-8"))