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 方法为私有方法,其中根据getpost方式进行逻辑判断


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

到此,这个R类已经被我们完善了,完整的代码,你应该从上面拼凑起来,你也可以直接翻到文章最后面,去github上直接查阅。

接下来,就是比较重要的爬虫代码部分了。这一次,我们可以简单的使用一下类和对象,并且加上简单的多线程操作。

首先,创建一个 ImageList 类,这个类第一件事情,需要获取我们爬取页面的总页码数目

这个步骤比较简单

  1. 获取网页源码
  2. 正则匹配末页元素
  3. 提取数字
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.__res.get_content(self.__start.format("1"),"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()

一会过后,就慢慢收图吧

github地址

这个版本的代码有点问题,对反爬处理的并不是很到位,大家先学习基础的,这个地方找时间,我在完善一下。

隐藏彩蛋,重要的事情说100遍:爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门

Python爬虫入门教程 5-100 27270图片爬取的更多相关文章

  1. Python爬虫入门教程:豆瓣Top电影爬取

        基本开发环境 Python 3.6 Pycharm 相关模块的使用 requests parsel csv 安装Python并添加到环境变量,pip安装需要的相关模块即可. 爬虫基本思路 一. ...

  2. Python爬虫入门教程 2-100 妹子图网站爬取

    妹子图网站爬取---前言 从今天开始就要撸起袖子,直接写Python爬虫了,学习语言最好的办法就是有目的的进行,所以,接下来我将用10+篇的博客,写爬图片这一件事情.希望可以做好. 为了写好爬虫,我们 ...

  3. Python爬虫入门教程 29-100 手机APP数据抓取 pyspider

    1. 手机APP数据----写在前面 继续练习pyspider的使用,最近搜索了一些这个框架的一些使用技巧,发现文档竟然挺难理解的,不过使用起来暂时没有障碍,估摸着,要在写个5篇左右关于这个框架的教程 ...

  4. Python爬虫入门教程 16-100 500px摄影师社区抓取摄影师数据

    写在前面 今天要抓取的网站为 https://500px.me/ ,这是一个摄影社区,在一个摄影社区里面本来应该爬取的是图片信息,可是我发现好像也没啥有意思的,忽然觉得爬取一下这个网站的摄影师更好玩一 ...

  5. Python爬虫入门教程 28-100 虎嗅网文章数据抓取 pyspider

    1. 虎嗅网文章数据----写在前面 今天继续使用pyspider爬取数据,很不幸,虎嗅资讯网被我选中了,网址为 https://www.huxiu.com/ 爬的就是它的资讯频道,本文章仅供学习交流 ...

  6. Python爬虫入门教程 17-100 CSD*博客抓取数据

    写在前面 写了一段时间的博客了,忽然间忘记了,其实CSD*博客频道的博客也是可以抓取的,所以我干了..... 其实这事情挺简单的,打开CSDN博客首页,他不是有个最新文章么,这个里面都是最新发布的文章 ...

  7. Python爬虫入门教程 33-100 电影评论数据抓取 scrapy

    1. 海王评论数据爬取前分析 海王上映了,然后口碑炸了,对咱来说,多了一个可爬可分析的电影,美哉~ 摘录一个评论 零点场刚看完,温导的电影一直很不错,无论是速7,电锯惊魂还是招魂都很棒.打斗和音效方面 ...

  8. Python爬虫入门教程 48-100 使用mitmdump抓取手机惠农APP-手机APP爬虫部分

    1. 爬取前的分析 mitmdump是mitmproxy的命令行接口,比Fiddler.Charles等工具方便的地方是它可以对接Python脚本. 有了它我们可以不用手动截获和分析HTTP请求和响应 ...

  9. Python爬虫入门教程 43-100 百思不得姐APP数据-手机APP爬虫部分

    1. Python爬虫入门教程 爬取背景 2019年1月10日深夜,打开了百思不得姐APP,想了一下是否可以爬呢?不自觉的安装到了夜神模拟器里面.这个APP还是比较有名和有意思的. 下面是百思不得姐的 ...

  10. Python爬虫入门教程 26-100 知乎文章图片爬取器之二

    1. 知乎文章图片爬取器之二博客背景 昨天写了知乎文章图片爬取器的一部分代码,针对知乎问题的答案json进行了数据抓取,博客中出现了部分写死的内容,今天把那部分信息调整完毕,并且将图片下载完善到代码中 ...

随机推荐

  1. Linux入门级

    Linux及其发行版 我安装过的Linux发行版centOS.Kali.Ubuntu.rebHat. Reference Linux发行版排行榜 开源协议 Reference 开源协议 场景 说明一个 ...

  2. kvm虚拟机存储管理

    一.kvm存储虚拟化介绍: 1.KVM 的存储虚拟化是通过存储池(Storage Pool)和卷Volume)来管理的. 2.Storage Pool 是宿主机上可以看到的一片存储空间,可以是多种型 ...

  3. MySql分割字符串【存储过程】

    MYSql没有表变量,通过函数无法返回表. 参考网址:https://bbs.csdn.net/topics/330021055 DELIMITER $$ USE `数据库`$$ DROP PROCE ...

  4. scrapy 教程

    pip install Scrapy 结果报错,那就一个一个安装吧 一.安装  1.pip install wheel 后面的都一样 pip install lxml pip install pyop ...

  5. Logstash 6.4.3 导入 csv 数据到 ElasticSearch 6.4.3

    本文实践最新版的Logstash从csv文件导入数据到ElasticSearch. 本文目录: 1.初始化ES.Kibana.Logstash 2.安装logstash文件导入.过滤器等插件 3.配置 ...

  6. Spring boot 处理 error 的套路

    Spring boot 处理 error 的基本流程: Controller -> 发生错误 -> BasicErrorController -> 根据 @RequestMappin ...

  7. hibernate框架中注意的几个问题

    使用hibernate框架中,session.createSQLQuery创建sql语句的时候遇到的问题 1.  select e.id,d.id from emp e,dept d where e. ...

  8. SpringBoot报错:Failed to load ApplicationContext(Mapped Statements collection already contains value)

    错误提示: Caused by: java.lang.IllegalArgumentException: Mapped Statements collection already contains v ...

  9. Linux shell编程 -test

    test 命令的格式非常简单 test condition condition 是test命令要测试的一系列参数和值.当用在if-then 语句中时,test 命令看起来是这样的 if test co ...

  10. CentOS7设置SVN自启动,提交报错,无权限.手动kill掉后重启,成功.

    参考文档:http://tieba.baidu.com/p/5174054662 最近想尝试在CentOS7上搭建SVN服务.遇到的问题大致如题,我这边再详细描述一下. 虚拟机:VMware® Wor ...