爬取网页(获取网页源码)

定义askURL方法来获取指定网页源码信息,askURL中需要重新定义head头部信息,用来伪装浏览器信息,防止网站反爬程序识别报错418。
如果没有设置头部信息,使用Python程序对网站进行爬取显示user-agent信息为:
在这里插入图片描述
这样很容易被反爬系统识别,这个是访问的httpbin.org测试网站,试一下豆瓣网:报错418,被发现我们是爬虫。
在这里插入图片描述
头部代理信息我们可以在打开网页的源代码中找到
在这里插入图片描述

修改头部代理再来测试爬取豆瓣网源码

#绕过反爬
# url="http://httpbin.org/get"
#url="http://httpbin.org/post"
url="http://douban.com"
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3947.100 Safari/537.36"
}#加入用户代理信息  伪装身份
req=urllib.request.Request(url=url,headers=headers)
response =urllib.request.urlopen(req)
print(response.read().decode("utf-8"))

爬取成功
在这里插入图片描述
askURL方法代码

def askURL(url):#得到指定的一个网页内容
    #模拟浏览器头部信息,向豆瓣服务器发送消息
    '''
    head={  #用户代理,表示告诉服务器我们是什么类型的机器、浏览器(告诉浏览器我们可以接收什么水平的信息)
        "User - Agent": "Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 69.0.3947.100Safari / 537.36"
    }
    '''#注意UserAgent的格式与网页上的格式,否则报错418
    head = {  # 用户代理,表示告诉服务器我们是什么类型的机器、浏览器(告诉浏览器我们可以接收什么水平的信息)
        "User-Agent": "Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 69.0.3947.100Safari / 537.36"
    }
    request=urllib.request.Request(url,headers=head)
    html=""
    try:
        response=urllib.request.urlopen(request)
        html=response.read().decode("utf-8")
        #print(html)
    except urllib.error.URLError as e:
        if hasattr(e,"code"):
            print(e.code)
        if hasattr(e,"reason"):
            print(e.reason)
    return html

解析数据

得到网页源代码以后,要分析源代码,需要从源代码中剥离我们需要的内容。

    #baseurl = "https://movie.douban.com/top250?start="
    for i in range(0,10):#调用获取网页函数10次
        url=baseurl+str(i*25)#start后依次为0、25、50……225
        html=askURL(url)#保存获取到的网页源码

我们经过分析网页网址格式已经知道,250部电影信息分布在10个网页,每个网页有25部电影信息,所以需要循环10次调用获取网页源码的方法。

先分析网页源代码:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
发现每个li,/li中间是一部电影的信息,然后点进第一个li,发现主体就是div class=“item”,然后就用到了我们的BeautifulSoup模块中的解析器.

解析网页需要用到BeautifulSoup模块

soup= BeautifulSoup(html, "html.parser")
        for item in soup.find_all('div',class_="item"):  #查找符合要求的字符串,形成列表
            #print(item)    #测试查看电影所有信息  #class是一个类别所以加一个_
            data=[] #保存一部电影的所有信息
            item=str(item)

这是爬取到的一部电影的item源代码

<!DOCTYPE html>
<div class="item">
<div class="pic">
<em class="">1</em>
<a href="https://movie.douban.com/subject/1292052/">
<img alt="肖申克的救赎" class="" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" width="100"/>
</a>
</div>
<div class="info">
<div class="hd">
<a class="" href="https://movie.douban.com/subject/1292052/">
<span class="title">肖申克的救赎</span>
<span class="title"> / The Shawshank Redemption</span>
<span class="other"> / 月黑高飞(港)  /  刺激1995(台)</span>
</a>
<span class="playable">[可播放]</span>
</div>
<div class="bd">
<p class="">
                            导演: 弗兰克·德拉邦特 Frank Darabont   主演: 蒂姆·罗宾斯 Tim Robbins /...<br/>
                            1994 / 美国 / 犯罪 剧情
                        </p>
<div class="star">
<span class="rating5-t"></span>
<span class="rating_num" property="v:average">9.7</span>
<span content="10.0" property="v:best"></span>
<span>2154144人评价</span>
</div>
<p class="quote">
<span class="inq">希望让人自由。</span>
</p>
</div>
</div>
</div>

通过分析第一步电影的网页源代码,我们来获取其中更精确的符合我们要求的信息。
首先举例获取电影的网页链接:

findLink=re.compile(r'<a href="(.*?)">')
#创建正则表达式对象,表示规则(字符串的模式)影片链接规则↑
#(.*?)表示一个组——中间的网址,提取源码中的电影链接
link=re.findall(findLink,item)[0]#re库通过正则表达式查找指定字符串的第一个符合条件的
            data.append(link)#将搜索到的网址添加到data中

同样的我们来获取更多我们所需要的信息,电影图片、电影名称、评分、点评人数、一句话概括、电影概述等等……
只需要编写相应的正则表达式来提取对应信息即可。

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>')#有0-多个数字(\d*)
#影片评价人数↑
findInq=re.compile(r'<span class="inq">(.*)</span>')
#一句话评价↑
findBd=re.compile(r'<p class="">(.*?)</p>',re.S)#影片相关内容有换行,记得re.S
#影片相关内容↑

正则表达式怎么得到的?用影片片名的表达式来说明
这是电影片名的源代码,所以正则表达式要求匹配除了电影名以外的字符串。

<span class="title">肖申克的救赎</span>

及正则表达式为:(前面加r的目的是为了不让中间出现的/进行转义,肖申克的救赎用(.*)来代替,表示多个任意字符,其余的字符串直接匹配)

r'<span class="title">(.*)</span>'

所以就得到匹配方法,方便提取信息的时候调用findTiTle。

findTiTle=re.compile(r'<span class="title">(.*)</span>')

然后跟获取网页链接的方法一样,将得到的信息都存入data中,每部电影的所有信息都放入一个datalist[]中,总体的代码如下:

import bs4  #网页解析,获取数据 beautiful soup 4
import re   #正则表达式,进行文字匹配
import urllib.request,urllib.error    #制定URL
import xlwt   #进行excel操作
import sqlite3   #进行SQLite数据库操作
from bs4 import BeautifulSoup

def main():
    baseurl = "https://movie.douban.com/top250?start="
    #爬取网页
    datalist=getData(baseurl)
    savepath=".\\豆瓣电影Top250.xls"
    #解析数据
    #保存数据
    # datalist=getData(baseurl)
    # savepath=".\\豆瓣Top250.xls"
    # saveData(savepath)
    #askURL(baseurl)

#中间有""所以用’‘可以不被影响,加r
findLink=re.compile(r'<a href="(.*?)">')#?表示.*出现0次到1次
#创建正则表达式对象,表示规则(字符串的模式)影片链接规则↑
#(.*?)表示一个组——中间的网址,提取源码中的电影链接
#<a href="https://movie.douban.com/subject/1291546/">   源码中的样子
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>')#有0-多个数字(\d*)
#影片评价人数↑
findInq=re.compile(r'<span class="inq">(.*)</span>')
#一句话评价↑
findBd=re.compile(r'<p class="">(.*?)</p>',re.S)#影片相关内容有换行,记得re.S
#影片相关内容↑

def getData(baseurl):#爬取网页
    datalist=[]
    for i in range(0,10):#调用获取网页函数10次
        url=baseurl+str(i*25)
        html=askURL(url)#保存获取到的网页源码
        #逐一解析
        soup= BeautifulSoup(html, "html.parser")
        for item in soup.find_all('div',class_="item"):  #查找符合要求的字符串,形成列表
            #print(item)    #测试查看电影所有信息  #class是一个类别所以加一个_
            data=[] #保存一部电影的所有信息
            item=str(item)
            #影片详情链接
            link=re.findall(findLink,item)[0]#re库通过正则表达式查找指定字符串的第一个符合条件的
            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("/","")#外文名前有个/,用replacce去掉/
                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+)?/>(\s+)?'," ",bd)#去掉<br/>
            bd=re.sub('/'," ",bd)#替换/
            data.append(bd.strip())#去掉前后空格

            datalist.append(data)#把处理好的一部电影信息放入datalist
    print(datalist)

    return datalist


def askURL(url):#得到指定的一个网页内容
    #模拟浏览器头部信息,向豆瓣服务器发送消息
    '''
    head={  #用户代理,表示告诉服务器我们是什么类型的机器、浏览器(告诉浏览器我们可以接收什么水平的信息)
        "User - Agent": "Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 69.0.3947.100Safari / 537.36"
    }
    '''#注意UserAgent的格式与网页上的格式,否则报错418
    head = {  # 用户代理,表示告诉服务器我们是什么类型的机器、浏览器(告诉浏览器我们可以接收什么水平的信息)
        "User-Agent": "Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 69.0.3947.100Safari / 537.36"
    }
    request=urllib.request.Request(url,headers=head)
    html=""
    try:
        response=urllib.request.urlopen(request)
        html=response.read().decode("utf-8")
        #print(html)
    except urllib.error.URLError as e:
        if hasattr(e,"code"):
            print(e.code)
        if hasattr(e,"reason"):
            print(e.reason)
    return html

def saveData(savepath):#保存数据
    print("save....")

if __name__=="__main__":
    main()

运行结果:可以看到得到了我们想要的结果。
在这里插入图片描述

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐