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
到此,这个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.__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()
一会过后,就慢慢收图吧
这个版本的代码有点问题,对反爬处理的并不是很到位,大家先学习基础的,这个地方找时间,我在完善一下。
隐藏彩蛋,重要的事情说100遍:爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门,爬虫入门
Python爬虫入门教程 5-100 27270图片爬取的更多相关文章
-
Python爬虫入门教程:豆瓣Top电影爬取
基本开发环境 Python 3.6 Pycharm 相关模块的使用 requests parsel csv 安装Python并添加到环境变量,pip安装需要的相关模块即可. 爬虫基本思路 一. ...
-
Python爬虫入门教程 2-100 妹子图网站爬取
妹子图网站爬取---前言 从今天开始就要撸起袖子,直接写Python爬虫了,学习语言最好的办法就是有目的的进行,所以,接下来我将用10+篇的博客,写爬图片这一件事情.希望可以做好. 为了写好爬虫,我们 ...
-
Python爬虫入门教程 29-100 手机APP数据抓取 pyspider
1. 手机APP数据----写在前面 继续练习pyspider的使用,最近搜索了一些这个框架的一些使用技巧,发现文档竟然挺难理解的,不过使用起来暂时没有障碍,估摸着,要在写个5篇左右关于这个框架的教程 ...
-
Python爬虫入门教程 16-100 500px摄影师社区抓取摄影师数据
写在前面 今天要抓取的网站为 https://500px.me/ ,这是一个摄影社区,在一个摄影社区里面本来应该爬取的是图片信息,可是我发现好像也没啥有意思的,忽然觉得爬取一下这个网站的摄影师更好玩一 ...
-
Python爬虫入门教程 28-100 虎嗅网文章数据抓取 pyspider
1. 虎嗅网文章数据----写在前面 今天继续使用pyspider爬取数据,很不幸,虎嗅资讯网被我选中了,网址为 https://www.huxiu.com/ 爬的就是它的资讯频道,本文章仅供学习交流 ...
-
Python爬虫入门教程 17-100 CSD*博客抓取数据
写在前面 写了一段时间的博客了,忽然间忘记了,其实CSD*博客频道的博客也是可以抓取的,所以我干了..... 其实这事情挺简单的,打开CSDN博客首页,他不是有个最新文章么,这个里面都是最新发布的文章 ...
-
Python爬虫入门教程 33-100 电影评论数据抓取 scrapy
1. 海王评论数据爬取前分析 海王上映了,然后口碑炸了,对咱来说,多了一个可爬可分析的电影,美哉~ 摘录一个评论 零点场刚看完,温导的电影一直很不错,无论是速7,电锯惊魂还是招魂都很棒.打斗和音效方面 ...
-
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爬虫入门教程 26-100 知乎文章图片爬取器之二
1. 知乎文章图片爬取器之二博客背景 昨天写了知乎文章图片爬取器的一部分代码,针对知乎问题的答案json进行了数据抓取,博客中出现了部分写死的内容,今天把那部分信息调整完毕,并且将图片下载完善到代码中 ...
随机推荐
-
创建mysql存储过程,调用 及删除
//创建表 create table test ( aid ) primary key auto_increment , nickname ), addtime ) ) //查看表结构 show co ...
-
帮朋友急招PHP、Android开发工程师 西安 工资8k-12k
PHP高级工程师岗位要求: 1. 有两年以上PHP开发经验, 2. 精通PHP+MySQL程序设计及开发,拥有良好的代码习惯,要求结构清晰,命名规范,逻辑性强,代码冗余率低. 3. 熟悉面向对象的软件 ...
-
window下查看TCP端口连接情况
window下查看TCP端口连接情况:netstat -ano -p tcp|findstr 10001
-
【技术帖】解决 Hudson jenkins 连接等待中 - Waiting for next av
今天构建项目发现如下问题: jenkins 连接等待中 - Waiting for next available executor 左下角那块一直不运行构建,一直在连接等待. 于是,进入一级页面, 右 ...
-
dell PowerEdge R720 自动重启分析
dell PowerEdge R720 自动重启分析 摘要: 一,问题描述: 在同一批服务器当中,碰到这样一台服务器,如果不跑任何服务时没有问题,但一跑任务就是自动重启.既然同样的系统别的服务器都没出 ...
-
php笔记(四)PHP类和对象之对象继承
建立一个Truck类,扩展Car类,并覆盖speedUp方法,使速度累加50 <?php class Car { public $speed = 0; //汽车的起始速度是0 public fu ...
-
!学习笔记:前端测试 、前端调试、console 等
http://www.cnblogs.com/rubekid/p/4851988.html 你真的了解 console 吗 2014 http://www.codeceo.com/article/ja ...
-
[LeetCode] 441. Arranging Coins_Easy tag: Math
You have a total of n coins that you want to form in a staircase shape, where every k-th row must ha ...
-
如何改变输出方式(让printf输出结果保存到TXT文本中)
查阅相关资料,汇总如下: #include <stdio.h> #include <stdlib.h> int main() { char money= 's'; char a ...
-
解决spring boot JavaMailSender部分收件人错误导致发送失败的问题
使用spring boot通常使用spring-boot-starter-mail进行邮件的发送.当进行邮件群发的话,如果一个收件人的地址错误,会导致所有邮件都发送失败.因此我们需要在邮件发送失败的时 ...