Python爬虫入门教程: 27270图片爬取
今天继续爬取一个网站,http://www.27270.com/ent/meinvtupian/
这个网站具备反爬,so我们下载的代码有些地方处理的也不是很到位,大家重点学习思路,有啥建议可以在评论的地方跟我说说。
为了以后的网络请求操作方向,我们这次简单的进行一些代码的封装操作。
在这里你可以先去安装一个叫做 retrying
的模块
pip install retrying
这个模块的具体使用,自己去百度吧。嘿嘿哒~
在这里我使用了一个随机产生user_agent的方法
import requests from retrying import retry import random import datetime class R: def __init__(self,method="get",params=None,headers=None,cookies=None): # do something def get_headers(self): user_agent_list = [ \ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" \ "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", \ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", \ "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", \ "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", \ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", \ "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", \ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \ "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \ "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \ "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \ "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \ "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", \ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", \ "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24" ] UserAgent = random.choice(user_agent_list) headers = {'User-Agent': UserAgent} return headers #other code
retrying
最简单的使用就是给你想不断重试的方法加上 装饰器 @retry
在这里,我希望网络请求模块尝试3次之后,在报错!
同时在R类
初始化方法中增加一些必备的参数,你可以直接看下面的代码
__retrying_requests 方法为私有方法,其中根据get和post方式进行逻辑判断 import requests from retrying import retry import random import datetime class R: def __init__(self,method="get",params=None,headers=None,cookies=None): #do something def get_headers(self): # do something @retry(stop_max_attempt_number=3) def __retrying_requests(self,url): if self.__method == "get": response = requests.get(url,headers=self.__headers,cookies=self.__cookies,timeout=3) else: response = requests.post(url,params=self.__params,headers=self.__headers,cookies=self.__cookies,timeout=3) return response.content # other code
网络请求的方法已经声明完毕,并且返回 response.content
数据流
下面基于这个私有方法,增加一个获取网络文本的方法和一个获取网络文件的方法。同步完善类的初始化方法,在开发中发现,我们要爬取的网页编码是gb2312
所以还需要给某些方法增加一个编码参数
import requests from retrying import retry import random import datetime class R: # 类的初始化方法 def __init__(self,method="get",params=None,headers=None,cookies=None): self.__method = method myheaders = self.get_headers() if headers is not None: myheaders.update(headers) self.__headers = myheaders self.__cookies = cookies self.__params = params def get_headers(self): # do something @retry(stop_max_attempt_number=3) def __retrying_requests(self,url): # do something # get请求 def get_content(self,url,charset="utf-8"): try: html_str = self.__retrying_requests(url).decode(charset) except: html_str = None return html_str def get_file(self,file_url): try: file = self.__retrying_requests(file_url) except: file = None return file #小编整理一套Python资料和PDF,有需要Python学习资料可以加学习群:1004391443,反正闲着也是闲着呢,不如学点东西啦~~
到此,这个R类
已经被我们完善了,完整的代码,你应该从上面拼凑起来,你也可以直接翻到文章最后面,去github上直接查阅。
接下来,就是比较重要的爬虫代码部分了。这一次,我们可以简单的使用一下类和对象,并且加上简单的多线程操作。
首先,创建一个 ImageList
类,这个类第一件事情,需要获取我们爬取页面的总页码数目
这个步骤比较简单
- 获取网页源码
- 正则匹配末页元素
- 提取数字
import http_help as hh # 这个http_help 是我上面写到的那个R类 import re import threading import time import os import requests # 获取所有待爬取的URL列表 class ImageList(): def __init__(self): self.__start = "http://www.27270.com/ent/meinvtupian/list_11_{}.html" # URL模板 # 头文件 self.__headers = {"Referer":"http://www.27270.com/ent/meinvtupian/", "Host":"www.27270.com" } self.__res = hh.R(headers=self.__headers) # 初始化访问请求 def run(self): page_count = int(self.get_page_count()) if page_count==0: return urls = [self.__start.format(i) for i in range(1,page_count)] return urls # 正则表达式匹配末页,分析页码 def get_page_count(self): # 注意这个地方需要传入编码 content = self."),"gb2312") pattern = re.compile("<li><a href='list_11_(\d+?).html' target='_self'>末页</a></li>") search_text = pattern.search(content) if search_text is not None: count = search_text.group(1) return count else: return 0 if __name__ == '__main__': img = ImageList() urls = img.run()
上面的代码注意get_page_count
方法,该方法已经获取到了末尾的页码
我们在run
方法内部,通过一个列表生成器
urls = [self.__start.format(i) for i in range(1,page_count)]
批量把要爬取的所有链接都生成完毕。
27270图片----分析上面爬取到的URL列表,捕获详情页
我们采用生产者和消费者模型,就是一个抓取链接图片,一个下载图片,采用多线程的方式进行操作,需要首先引入
import threading
import time
完整代码如下
import http_help as hh import re import threading import time import os import requests urls_lock = threading.Lock() #url操作锁 imgs_lock = threading.Lock() #图片操作锁 imgs_start_urls = [] class Product(threading.Thread): # 类的初始化方法 def __init__(self,urls): threading.Thread.__init__(self) self.__urls = urls self.__headers = {"Referer":"http://www.27270.com/ent/meinvtupian/", "Host":"www.27270.com" } self.__res = hh.R(headers=self.__headers) # 链接抓取失败之后重新加入urls列表中 def add_fail_url(self,url): print("{}该URL抓取失败".format(url)) global urls_lock if urls_lock.acquire(): self.__urls.insert(0, url) urls_lock.release() # 解锁 # 线程主要方法 def run(self): print("*"*100) while True: global urls_lock,imgs_start_urls if len(self.__urls)>0: if urls_lock.acquire(): # 锁定 last_url = self.__urls.pop() # 获取urls里面最后一个url,并且删除 urls_lock.release() # 解锁 print("正在操作{}".format(last_url)) content = self.__res.get_content(last_url,"gb2312") # 页面注意编码是gb2312其他格式报错 if content is not None: html = self.get_page_list(content) if len(html) == 0: self.add_fail_url(last_url) else: if imgs_lock.acquire(): imgs_start_urls.extend(html) # 爬取到图片之后,把他放在待下载的图片列表里面 imgs_lock.release() time.sleep(5) else: self.add_fail_url(last_url) else: print("所有链接已经运行完毕") break def get_page_list(self,content): # 正则表达式 pattern = re.compile('<li> <a href="(.*?)" title="(.*?)" class="MMPic" target="_blank">.*?</li>') list_page = re.findall(pattern, content) return list_page
上述代码中比较重要的有
threading.Lock() 锁的使用,在多个线程之间操作全局变量,需要进行及时的锁定;
其他的注意内容,我已经添加在注释里面,只要你按着步骤一点点的写,并且加入一些自己微妙的理解,就可以搞定。
到现在为止,我们已经抓取到了所有的图片地址,我把他存放在了一个全局的变量里面 imgs_start_urls
那么现在又来了
这个列表里面存放的是 http://www.27270.com/ent/meinvtupian/2018/298392.html
这样的地址,当你打开这个页面之后,你会发现只有一张图片 ,并且下面有个分页。
点击分页之后,就知道规律了
http://www.27270.com/ent/meinvtupian/2018/298392.html
http://www.27270.com/ent/meinvtupian/2018/298392_2.html
http://www.27270.com/ent/meinvtupian/2018/298392_3.html
http://www.27270.com/ent/meinvtupian/2018/298392_4.html
....
当你进行多次尝试之后,你会发现,后面的链接完全可以靠拼接完成,如果没有这个页面,那么他会显示?
好了,如果你进行了上面的操作,你应该知道接下来怎么实现啦!
我把所有的代码,都直接贴在下面,还是用注释的方式给大家把最重要的地方标注出来
class Consumer(threading.Thread): # 初始化 def __init__(self): threading.Thread.__init__(self) self.__headers = {"Referer": "http://www.27270.com/ent/meinvtupian/", "Host": "www.27270.com"} self.__res = hh.R(headers=self.__headers) # 图片下载方法 def download_img(self,filder,img_down_url,filename): file_path = "./downs/{}".format(filder) # 判断目录是否存在,存在创建 if not os.path.exists(file_path): os.mkdir(file_path) # 创建目录 if os.path.exists("./downs/{}/{}".format(filder,filename)): return else: try: # 这个地方host设置是个坑,因为图片为了防止盗链,存放在另一个服务器上面 img = requests.get(img_down_url,headers={"Host":"t2.hddhhn.com"},timeout=3) except Exception as e: print(e) print("{}写入图片".format(img_down_url)) try: # 图片写入不在赘述 with open("./downs/{}/{}".format(filder,filename),"wb+") as f: f.write(img.content) except Exception as e: print(e) return def run(self): while True: global imgs_start_urls,imgs_lock if len(imgs_start_urls)>0: if imgs_lock.acquire(): # 锁定 img_url = imgs_start_urls[0] #获取到链接之后 del imgs_start_urls[0] # 删掉第0项 imgs_lock.release() # 解锁 else: continue # http://www.27270.com/ent/meinvtupian/2018/295631_1.html #print("图片开始下载") img_url = img_url[0] start_index = 1 base_url = img_url[0:img_url.rindex(".")] # 字符串可以当成列表进行切片操作 while True: img_url ="{}_{}.html".format(base_url,start_index) # url拼接 content = self.__res.get_content(img_url,charset="gbk") # 这个地方获取内容,采用了gbk编码 if content is not None: pattern = re.compile('<div class="articleV4Body" id="picBody">[\s\S.]*?img alt="(.*?)".*? src="(.*?)" />') # 匹配图片,匹配不到就代表本次操作已经完毕 img_down_url = pattern.search(content) # 获取到了图片地址 if img_down_url is not None: filder = img_down_url.group(1) img_down_url = img_down_url.group(2) filename = img_down_url[img_down_url.rindex("/")+1:] self.download_img(filder,img_down_url,filename) #下载图片 else: print("-"*100) print(content) break # 终止循环体 else: print("{}链接加载失败".format(img_url)) if imgs_lock.acquire(): # 锁定 imgs_start_urls.append(img_url) imgs_lock.release() # 解锁 start_index+=1 # 上文描述中,这个地方需要不断进行+1操作
所有的代码都在上面了,关键的地方我尽量加上了标注,你可以细细的看一下,实在看不明白,就多敲几遍,因为没有特别复杂的地方,好多都是逻辑。
最后附上main部分的代码,让我们的代码跑起来
if __name__ == '__main__': img = ImageList() urls = img.run() for i in range(1,2): p = Product(urls) p.start() for i in range(1,2): c = Consumer() c.start()
一会过后,就慢慢收图吧
Python爬虫入门教程: 27270图片爬取的更多相关文章
- Python爬虫入门教程 64-100 反爬教科书级别的网站-汽车之家,字体反爬之二
说说这个网站 汽车之家,反爬神一般的存在,字体反爬的鼻祖网站,这个网站的开发团队,一定擅长前端吧,2019年4月19日开始写这篇博客,不保证这个代码可以存活到月底,希望后来爬虫coder,继续和汽车之 ...
- python爬虫调用搜索引擎及图片爬取实战
实战三-向搜索引擎提交搜索请求 关键点:利用搜索引擎提供的接口 百度的接口:wd="要搜索的内容" 360的接口:q="要搜索的内容" 所以我们只要把我们提交给 ...
- python爬虫入门新手向实战 - 爬取猫眼电影Top100排行榜
本次主要爬取Top100电影榜单的电影名.主演和上映时间, 同时保存为excel表个形式, 其他相似榜单也都可以依葫芦画瓢 首先打开要爬取的网址https://maoyan.com/board/4, ...
- Python爬虫入门教程 46-100 Charles抓取手机收音机-手机APP爬虫部分
1. 手机收音机-爬前叨叨 今天选了一下,咱盘哪个APP呢,原计划是弄荔枝APP,结果发现竟然没有抓到数据,很遗憾,只能找个没那么圆润的了.搜了一下,找到一个手机收音机 下载量也是不错的. 2. 爬虫 ...
- Python爬虫入门教程 45-100 Charles抓取兔儿故事-下载小猪佩奇故事-手机APP爬虫部分
1. Charles抓取兔儿故事背景介绍 之前已经安装了Charles,接下来我将用两篇博客简单写一下关于Charles的使用,今天抓取一下兔儿故事里面关于小猪佩奇的故事. 爬虫编写起来核心的重点是分 ...
- Python爬虫入门教程 48-100 使用mitmdump抓取手机惠农APP-手机APP爬虫部分
1. 爬取前的分析 mitmdump是mitmproxy的命令行接口,比Fiddler.Charles等工具方便的地方是它可以对接Python脚本. 有了它我们可以不用手动截获和分析HTTP请求和响应 ...
- Python爬虫入门教程 43-100 百思不得姐APP数据-手机APP爬虫部分
1. Python爬虫入门教程 爬取背景 2019年1月10日深夜,打开了百思不得姐APP,想了一下是否可以爬呢?不自觉的安装到了夜神模拟器里面.这个APP还是比较有名和有意思的. 下面是百思不得姐的 ...
- Python爬虫学习三------requests+BeautifulSoup爬取简单网页
第一次第一次用MarkDown来写博客,先试试效果吧! 昨天2018俄罗斯世界杯拉开了大幕,作为一个伪球迷,当然也得为世界杯做出一点贡献啦. 于是今天就编写了一个爬虫程序将腾讯新闻下世界杯专题的相关新 ...
- Python爬虫入门教程 26-100 知乎文章图片爬取器之二
1. 知乎文章图片爬取器之二博客背景 昨天写了知乎文章图片爬取器的一部分代码,针对知乎问题的答案json进行了数据抓取,博客中出现了部分写死的内容,今天把那部分信息调整完毕,并且将图片下载完善到代码中 ...
- Python爬虫入门教程 3-100 美空网数据爬取
美空网数据----简介 从今天开始,我们尝试用2篇博客的内容量,搞定一个网站叫做"美空网"网址为:http://www.moko.cc/, 这个网站我分析了一下,我们要爬取的图片在 ...
随机推荐
- Vue.js实战 5.5章 购物车
<!DOCTYPE html> <html lang="en"> <head> <title>购物车示例</title> ...
- js实现页面的全屏与退出
1.在data里面定义: data(){ return{ isScreen:false, } } //是否显示全屏 fullScreen(event){ this.isScreen = !this.i ...
- 为什么要用Go语言做后端
FMZ数字货币量化平台 www.fmz.com, 后端使用Go语言,这里是创始人Zero谈论使用Go语言所带了的便利.原帖地址:https://www.zhihu.com/question/27172 ...
- SpringBoot整合SpringSecurity简单案例
在我们开发项目的过程中经常会用到一些权限管理框架,Java领域里边经常用的可能就是shiro了,与之对应的还有SpringSecurity,SpringSecurity可以说是非常强大,与Spring ...
- Shape Drawable Resources
1,示例 它们的代码如下: shape_oval.xml <?xml version="1.0" encoding="utf-8"?> <sh ...
- [ TJOI 2012 ] 防御
\(\\\) Description 有 \(n\) 人,第 \(i\) 个人有一个护甲值 \(a_i\). 有 \(m\) 次操作,分为以下两种: \(A\ l\ r\ x\) 对编号在 \([l, ...
- String field contains invalid UTF-8 data when serializing a protocol buffer. Use the 'bytes' type if you intend to send raw bytes.
[libprotobuf ERROR google/protobuf/wire_format.cc:1053] String field contains invalid UTF-8 data whe ...
- ES6十大常用特性
. Default Parameters(默认参数) in ES6 2. Arrow Functions (箭头函数)in ES6 3. Block-Scoped Constructs ...
- Java 基础入门随笔(10) JavaSE版——单例设计模式
设计模式:对问题行之有效的解决方式.其实它是一种思想. 1.单例设计模式. 解决的问题:就是可以保证一个类在内存中的对象唯一性.(单个实例) 使用单例设计模式需求:必须对于多个程序使用同一个配置信息对 ...
- python爬虫(房天下)
房天下 import requests res = requests.get('http://esf.sz.fang.com/') #res.text from bs4 import Beautifu ...