一文让你彻底掌握python爬虫的编写(代码可以直接使用!)

最近闲来无事研究了下python的爬虫机制,为了以后回顾,所以写篇博文详细讲下过程。(以爬取某网站图片为例)

示范网站:https://www.dpm.org.cn/lights/royal.html

 

首先我们需要分析我们要爬取的网页,

我们需要得到以下几个内容:

1:网页的url(用以request发送请求)

2:我们所要爬取的内容在哪里(用正则去抓取)

3:我们要爬取的具体内容的url

以下详细说明:

第一步:获得url:https://www.dpm.org.cn/lights/royal.html

第二步,F12进入检查模式(我用的google浏览器)

找到图片在哪个子标签里(需要有一点html知识),网页html内容很多,我们将鼠标放在某一行,这一行对应网页里的块就会高亮,很方便就可以找到图片在哪里子标签里。

例子中的图片在class='pic'的div里,具体的地址在img标签中,属性src。

第三步:有很多网站src对应的地址并不是完整的地址,例如会去掉头部地址,只有子目录查找的地址,这时候我们需要自己补齐完整的url。(头部地址基本都是固定的,也就是网站的地址,用字符串拼接即可)

OK。我们获得了写代码需要的所有先验信息,可以直接写了。

先贴一个获取图片地址的代码

    def get_pic_url(self):
        web_url = self.web_url
        # 使用requests获取网页html里的内容
        req = requests.get(web_url)
        # 将Unicode转码位utf-8,不转化会是乱码
        req.encoding = "utf-8"
        # 解析里面的内容
        bs = bs4.BeautifulSoup(req.text, features='html.parser')
        # 正则搜索我们要找的内容
        sub_web_url = bs.find_all("div", {"class": {"pic"}})
        img_web_url = []
        # 存储找到的图片具体的地址
        for i in sub_web_url:
            img_web_url.append(i.find("img").get("src"))
        return img_web_url

web_url就是第一步得到的url。

第二步得到的先验信息用在正则搜索里。bs.find_all会得到所有class='pic'的div文本(列表形式存储)

我们只需要遍历div文本列表,继续用正则搜索标签为img,属性为src的文本,也就是图片的具体地址。

到这一步,我们已经获得了了完整的图片具体地址

图片地址例如https://img.dpm.org.cn/Uploads/Picture/2020/04/28/s5ea8381900a46.jpg这样的形式

接着只需要存在本地。

    def save_img(self, img_url):
        save_path=self.save_path
        if not os.path.exists(save_path):
            os.mkdir(save_path)
        with open(os.path.join(save_path, os.path.basename(img_url)), 'wb') as f:
            f.write(requests.get(img_url).content)
        print(os.path.basename(img_url) + ' save success!')

这里的img_url就是上面得到的img_web_url里的元素值。用requests.get获得图片网页的文本,再存储到本地即可。

到这里整个爬虫程序也就结束了,是不是很简单?下面贴上完整代码。

import bs4
import requests
import os
import multiprocessing
from multiprocessing import Pool
"""爬取图片"""


class Picture:
    def __init__(self, web_url, save_path):
        self.web_url = web_url
        self.save_path = save_path

    def get_pic_url(self):
        web_url = self.web_url
        # 使用requests获取网页html里的内容
        req = requests.get(web_url)
        # 将Unicode转码位utf-8,不转化会是乱码
        req.encoding = "utf-8"
        # 解析里面的内容
        bs = bs4.BeautifulSoup(req.text, features='html.parser')
        # 正则搜索我们要找的内容
        sub_web_url = bs.find_all("div", {"class": {"pic"}})
        img_web_url = []
        # 存储找到的图片具体的地址
        for i in sub_web_url:
            img_web_url.append(i.find("img").get("src"))
        return img_web_url

    def save_img(self, img_url):
        save_path=self.save_path
        if not os.path.exists(save_path):
            os.mkdir(save_path)
        with open(os.path.join(save_path, os.path.basename(img_url)), 'wb') as f:
            f.write(requests.get(img_url).content)
        print(os.path.basename(img_url) + ' save success!')

    def start(self):
        pic_urls=self.get_pic_url()
        return pic_urls


if "__main__" == __name__:
    url='https://www.dpm.org.cn/lights/royal.html'
    save_path='I:\故宫壁纸'
    p=Picture(url, save_path)
    urls=p.start()
    cores = multiprocessing.cpu_count()
    pool = Pool(cores)
    for url in urls:
        pool.apply_async(p.save_img, (url,))
    pool.close()
    pool.join()
    print('所有图片已下完')

大家可以看到我把Picture类里的方法拿到main函数里单独运行,目的是为了多线程(Pool只能在main函数里写)运行。如果你不需要多线程,把Pool的操作都删除,直接在Picture类的start方法里完成整个程序即可。

如果发现了403错误,可以在用request请求之前添加headers信息,例如:

headers = {'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" }    #浏览器请求头,有时python直接获取图片时防盗链会踢出,所以我们假装是在用浏览器

具体添加到什么程度,比如cookie,Referer这些加不加由你当时的具体情况决定,这取决于你要爬取的网站反爬虫功能有多强。

如何查看自己浏览器的请求头请自行baidu,这里就不赘述了。

 

爬取结果图:
 

我踩过的坑

我原本程序用的urllib库,但一直403,怎么修改headers都没用,后面放弃了,使用了request+bs4这一套方案,连headers都不用就能跑通,至今不知道是为什么。大家如果用urllib库一直403,可以选择改用request。

------------------------------------------------------------------------------------------------------------------------------------------------------------

2020-5-5凌晨:

想想再加点东西,还是以这个网站为例子,我们看到这一页图片只有几张,下面还有翻页的提示

如果我们想将整个网站所有壁纸一次性全爬到呢?

很简单,从第二步做起,我们分析得到翻页内容块在class='pages'的div标签里,页面具体地址在标签为a,属性href中,那么仍然使用正则去搜索得到这些地址,这些地址也是我们的url,遍历再跑一遍即可。这里我们发现,网页地址没有头部地址,那么在遍历url时添加上head='https://www.dpm.org.cn/'头部地址即可。并且我们发现网页的命令是有规律的,最后一个元素代表页面下标,其他完全相同,那都不需要正则,自己构造一个循环range(2,110)就行了。

'https://www.dpm.org.cn/lights/royal/p/'+str(i)+'.html'

另外,上文的多线程是用在存图片上(因为就一个网页),这里我们有110个网页要存,那可以将多线程用于处理整个网页上,将上面存储图片的程序全在类Picture里完成,在main函数里多线程并行调用Picture类即可。

具体代码就不改了,有python的基础的话,大家应该很容易就能修改我给的源码。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值