【目录】2019-04-02
image.png第一部分:前言
一、所需工具(4个)
jupyter notebook(单进程用)、mongodb(存储数据用)、studio-3t(查看数据用)、sublime(多进程用)
二、主要知识点(4个)
urlib库、requests库、BeautifulSoup库、正则表达式(很少)
三、操作流程(3个阶段)
- 1、单个模块运行:单个方法模块调试通畅,保证子程序没有问题
- 2、单进程运行:参数写死,请求一个图集的结果
- 3、多进程运行:参数可变,请求多个图集的结果
第二部分:正文
一、分析目标网站(4个关键问题)
1、确认数据是怎么加载的--找到ajax文件
image.png
2、找到各个图集的区别--发现offset变化规律
下拉加载,依次点击XHR文件查看,看到offset变化规律:0,20,40.....
image.png
3、定位详情页链接--在哪里?
各种尝试后,发现详情页链接在article_url这个参数中
image.png
4、定位图片链接--在哪里?
preview的源代码中可以发现,BASE_DATA.galleryInfo里面gallery这个参数中就含有url链接。测试一下,copy其中的一个url:消除“\\”后访问,发现就是图集中图片。
gallery中copy一个url:http://pb3.pstatp.com/origin/dfic-imagehandler/7e8da4a8-dad7-4951-bf81-78988fae40bb
二、设定思路步骤(9个步骤)
1、载入必要的包
# 1.导入必要的库:
import requests #请求网页用
from requests.exceptions import RequestException #做requests的异常处理
from urllib.parse import urlencode #url编码用
from bs4 import BeautifulSoup #网页解析用
import urllib #请求网页用
import json #格式转换用
import re #正则表达式用
import pymongo #连接数据库用
import os #路径相关的函数
from hashlib import md5 #图片命名用
from multiprocessing import Pool #建立多进程用
2、请求索引页
# 1.导入必要的库:
import requests #请求网页用
from requests.exceptions import RequestException #做requests的异常处理
from urllib.parse import urlencode #url编码用
from bs4 import BeautifulSoup #网页解析用
import urllib #请求网页用
import json #格式转换用
import re #正则表达式用
import pymongo #连接数据库用
import os #路径相关的函数
from hashlib import md5 #图片命名用
from multiprocessing import Pool #建立多进程用
keyword='街拍图片'
offset=0
#放在全局中,不要放在方法中,不然每次请求要重复写headers参数。
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64)","Referer":"https://www.toutiao.com/"}
# 2.获取索引页并分析:
def get_page_index(offset, keyword):
data = {
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': 20,
'cur_tab': 1, # cur_tab为3指的是图集板块,数过来第三个,若为1则指代综合板块
'from': 'search_tab'
}
url = 'https://www.toutiao.com/api/search/content/?' + urlencode(data)
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
print('请求索引页错误')
return None
#8、定义一个主函数,调用之前的方法
def main(offset):
html=get_page_index(offset,keyword)
print(html)
# 9、只运行本文件中的主函数
if __name__=='__main__':
main(offset)
预期结果:返回结果跟索引页的preview中一致
image.png
3、解析索引页,得到详情页url
# 1.导入必要的库:
import requests #请求网页用
from requests.exceptions import RequestException #做requests的异常处理
from urllib.parse import urlencode #url编码用
from bs4 import BeautifulSoup #网页解析用
import urllib #请求网页用
import json #格式转换用
import re #正则表达式用
import pymongo #连接数据库用
import os #路径相关的函数
from hashlib import md5 #图片命名用
from multiprocessing import Pool #建立多进程用
keyword='街拍图片'
offset=20
#放在全局中,不要放在方法中,不然每次请求要重复写headers参数。
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64)","Referer":"https://www.toutiao.com/"}
# 2.获取索引页并分析:
def get_page_index(offset, keyword):
data = {
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': 20,
'cur_tab': 1, # cur_tab为3指的是图集板块,数过来第三个,若为1则指代综合板块
'from': 'search_tab'
}
url = 'https://www.toutiao.com/api/search/content/?' + urlencode(data) #url写错,卡了3天啊
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
print('请求索引页错误')
return None
# 3、解析索引页内容
# 分析ajax请求的返回结果,拿到详情页的url
def parse_page_index(html):
data = json.loads(html) # 加载返回的json数据
if data and 'data' in data.keys(): #确保返回的信息中含有data这个信息
for item in data.get('data'):
yield item.get('article_url') #构造一个生成器
#8、定义一个主函数,调用之前的方法
def main(offset):
html=get_page_index(offset,keyword)
for url in parse_page_index(html): #返回的是一个迭代器,每次输出一个网址
print(url)
# 9、只运行本文件中的主函数
if __name__=='__main__':
main(offset)
预期结果:详情页的url
image.png
4、请求详情页
5、解析详情页,得到目标图片的url
# 1.导入必要的库:
import requests #请求网页用
from requests.exceptions import RequestException #做requests的异常处理
from urllib.parse import urlencode #url编码用
from bs4 import BeautifulSoup #网页解析用
import urllib #请求网页用
import json #格式转换用
import re #正则表达式用
import pymongo #连接数据库用
import os #路径相关的函数
from hashlib import md5 #图片命名用
from multiprocessing import Pool #建立多进程用
keyword='街拍图片'
offset=20
#放在全局中,不要放在方法中,不然每次请求要重复写headers参数。
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64)","Referer":"https://www.toutiao.com/"}
# 2.获取索引页并分析:
def get_page_index(offset, keyword):
data = {
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': 20,
'cur_tab': 1, # cur_tab为3指的是图集板块,数过来第三个,若为1则指代综合板块
'from': 'search_tab'
}
url = 'https://www.toutiao.com/api/search/content/?' + urlencode(data) #url写错,卡了3天啊
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
print('请求索引页错误')
return None
# 3、解析索引页内容
# 分析ajax请求的返回结果,拿到详情页的url
def parse_page_index(html):
data = json.loads(html) # 加载返回的json数据
if data and 'data' in data.keys(): #确保返回的信息中含有data这个信息
for item in data.get('data'):
yield item.get('article_url') #构造一个生成器
# 4、请求详情页的内容
def get_page_detail(url):
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
print('详情页页错误', url)
return None
# 5、解析详情页的内容
def parse_page_detail(html,url):
try:
soup = BeautifulSoup(html, 'lxml') #解析详情页的内容
title = soup.select('title')[0].get_text() #获取文章title
images_pattern = re.compile('gallery: JSON.parse\("(.*?)"\)',re.S) #确定匹配模式
result = re.search(images_pattern,html) #匹配内容
str=re.sub(r'(\\)','',result.group(1)) #去掉url链接中防作弊的多余的双斜线“\\”
if str: #如果匹配到内容,执行接下来的操作
data = json.loads(str)
if data and 'sub_images' in data.keys(): #确保返回的信息中含有sub_images这个信息
sub_images=data.get('sub_images')
images=[item.get('url') for item in sub_images] #提取sub_images中图片的url链接
return{
'title':title, #详情页标题
'url':url, #详情页链接
'images':images #图片链接
}
except:
return None #跳过异常继续执行
#8、定义一个主函数,调用之前的方法
def main(offset):
html=get_page_index(offset,keyword)
for url in parse_page_index(html): #返回的是一个迭代器,每次输出一个网址
html = get_page_detail(url)
if html:
result=parse_page_detail(html,url) #传入详情页链接、详情页内容,进行解析
print(result)
# 9、只运行本文件中的主函数
if __name__=='__main__':
main(offset)
预期结果:详情页标题、详情页链接、图片链接
image.png
6、下载图片 to 本地文件夹
7、返回数据 to mongodb
# 1.导入必要的库:
import requests #请求网页用
from requests.exceptions import RequestException #做requests的异常处理
from urllib.parse import urlencode #url编码用
from bs4 import BeautifulSoup #网页解析用
import urllib #请求网页用
import json #格式转换用
import re #正则表达式用
import pymongo #连接数据库用
from hashlib import md5 #图片命名用
import os
from multiprocessing import Pool #建立多进程用
keyword='街拍图片'
offset=100
MONGO_URL='localhost'
MONGO_DB='toutiao'
MONGO_TABLE='toutiao'
client = pymongo.MongoClient(MONGO_URL) # 连接MongoDB
db = client[MONGO_DB] # 如果已经存在连接,否则创建数据库
#放在全局中,不要放在方法中,不然每次请求要重复写headers参数。
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64)","Referer":"https://www.toutiao.com/"}
# 2.获取索引页并分析:
def get_page_index(offset, keyword):
data = {
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': 20,
'cur_tab': 1, # cur_tab为3指的是图集板块,数过来第三个,若为1则指代综合板块
'from': 'search_tab'
}
url = 'https://www.toutiao.com/api/search/content/?' + urlencode(data) #url写错,卡了3天啊
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
print('请求索引页错误')
return None
# 3、解析索引页内容
# 分析ajax请求的返回结果,拿到详情页的url
def parse_page_index(html):
data = json.loads(html) # 加载返回的json数据
if data and 'data' in data.keys(): #确保返回的信息中含有data这个信息
for item in data.get('data'):
yield item.get('article_url') #构造一个生成器
# 4、请求详情页的内容
def get_page_detail(url):
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
print('详情页页错误', url)
return None
# 5、解析详情页的内容
def parse_page_detail(html,url):
try:
soup = BeautifulSoup(html, 'lxml') #解析详情页的内容
title = soup.select('title')[0].get_text() #获取文章title
images_pattern = re.compile('gallery: JSON.parse\("(.*?)"\)',re.S) #确定匹配模式
result = re.search(images_pattern,html) #匹配内容
str=re.sub(r'(\\)','',result.group(1)) #去掉url链接中防作弊的多余的双斜线“\\”
if str: #如果匹配到内容,执行接下来的操作
data = json.loads(str)
if data and 'sub_images' in data.keys(): #确保返回的信息中含有sub_images这个信息
sub_images=data.get('sub_images')
images=[item.get('url') for item in sub_images] #提取sub_images中图片的url链接
for image in images:
download_img(image) #调用一个方法,下载图片
return{
'title':title, #详情页标题
'url':url, #详情页链接
'images':images #图片链接
}
except:
return None #跳过异常继续执行
# 6、存储到mongodb
def save_to_mongo(result):
if result:
if db[MONGO_TABLE].insert(result): # 插入数据
print('存储成功', result)
return True
return False
# 7、下载图片(进度+存图)
def download_img(url):
print('正在下载', url)
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
save_img(response.content) #content返回二进制内容,图片一般返回content
else:
return None
except RequestException:
print('下载图片错误', url)
return None
#存储图片方法
def save_img(content):
#生成目标文件路径,图片用md5命名,保证不重复
file_path = '{0}/{1}.{2}'.format(r'C:\Users\luna\jiepai3', md5(content).hexdigest(), 'jpg')
if not os.path.exists(file_path):
with open(file_path, 'wb')as f:
f.write(content)
f.close()
#8、定义一个主函数,调用之前的方法
def main(offset):
html=get_page_index(offset,keyword)
for url in parse_page_index(html): #返回的是一个迭代器,每次输出一个网址
html = get_page_detail(url)
if html:
result=parse_page_detail(html,url) #传入详情页链接、详情页内容,进行解析,下载图片
save_to_mongo(result) #把返回内容存入数据库
# 9、只运行本文件中的主函数
if __name__=='__main__':
main(offset)
预期结果:
(1)运行结果
image.png
(2)本地文件夹载入图片
image.png
(3)mongodb中载入数据
image.png
8、调用主函数
9、启动多进程
# 1.导入必要的库:
import requests #请求网页用
from requests.exceptions import RequestException #做requests的异常处理
from urllib.parse import urlencode #url编码用
from bs4 import BeautifulSoup #网页解析用
import urllib #请求网页用
import json #格式转换用
import re #正则表达式用
import pymongo #连接数据库用
import os #路径相关的函数
from hashlib import md5 #图片命名用
from multiprocessing import Pool #建立多进程用
GROUP_START=1
GROUP_END=20
keyword='街拍图片'
MONGO_URL='localhost'
MONGO_DB='toutiao'
MONGO_TABLE='toutiao'
client = pymongo.MongoClient(MONGO_URL) # 连接MongoDB
db = client[MONGO_DB] # 如果已经存在连接,否则创建数据库
#放在全局中,不要放在方法中,不然每次请求要重复写headers参数。
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64)","Referer":"https://www.toutiao.com/"}
# 2.获取索引页并分析:
def get_page_index(offset, keyword):
data = {
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': 20,
'cur_tab': 1, # cur_tab为3指的是图集板块,数过来第三个,若为1则指代综合板块
'from': 'search_tab'
}
url = 'https://www.toutiao.com/api/search/content/?' + urlencode(data) #url写错,卡了3天啊
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
print('请求索引页错误')
return None
# 3、解析索引页内容
# 分析ajax请求的返回结果,拿到详情页的url
def parse_page_index(html):
data = json.loads(html) # 加载返回的json数据
if data and 'data' in data.keys(): #确保返回的信息中含有data这个信息
for item in data.get('data'):
yield item.get('article_url') #构造一个生成器
# 4、请求详情页的内容
def get_page_detail(url):
try:
response = requests.get(url,headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
print('详情页页错误', url)
return None
# 5、解析详情页的内容
def parse_page_detail(html,url):
try:
soup = BeautifulSoup(html, 'lxml') #解析详情页的内容
title = soup.select('title')[0].get_text() #获取文章title
images_pattern = re.compile('gallery: JSON.parse\("(.*?)"\)',re.S) #确定匹配模式
result = re.search(images_pattern,html) #匹配内容
str=re.sub(r'(\\)','',result.group(1)) #去掉url链接中防作弊的多余的双斜线“\\”
if str: #如果匹配到内容,执行接下来的操作
data = json.loads(str)
if data and 'sub_images' in data.keys(): #确保返回的信息中含有sub_images这个信息
sub_images=data.get('sub_images')
images=[item.get('url') for item in sub_images] #提取sub_images中图片的url链接
for image in images:
download_img(image) #调用一个方法,下载图片
return{
'title':title, #详情页标题
'url':url, #详情页链接
'images':images #图片链接
}
except:
return None #跳过异常继续执行
# 6、存储到mongodb
def save_to_mongo(result):
if result:
if db[MONGO_TABLE].insert(result): # 插入数据
print('存储成功', result)
return True
return False
# 7、下载图片(进度+存图)
def download_img(url):
print('正在下载', url)
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
save_img(response.content) #content返回二进制内容,图片一般返回content
else:
return None
except RequestException:
print('下载图片错误', url)
return None
#存储图片方法
def save_img(content):
#生成目标文件路径,图片用md5命名,保证不重复
file_path = '{0}/{1}.{2}'.format(r'C:\Users\luna\jiepai3', md5(content).hexdigest(), 'jpg')
if not os.path.exists(file_path):
with open(file_path, 'wb')as f:
f.write(content)
f.close()
#8、定义一个主函数,调用之前的方法
def main(offset):
html=get_page_index(offset,keyword)
for url in parse_page_index(html): #返回的是一个迭代器,每次输出一个网址
html = get_page_detail(url)
if html:
result=parse_page_detail(html,url) #传入详情页链接、详情页内容,进行解析,下载图片
save_to_mongo(result) #把返回内容存入数据库
# 9、只运行本文件中的主函数
if __name__=='__main__':
groups = [i * 20 for i in list(range(GROUP_START,GROUP_END))] # python3 range()不能直接生成列表,需要list一下
pool = Pool() #创建进程池
pool.map(main,groups) # 第一个参数是函数,第二个参数是一个迭代器,将迭代器中的数字作为参数依次传入函数中
预期结果:
(1)图片大量存入文件夹
(2)mongodb中数据条数变多
第三部分:后记
一、耗时:2天
二、感受(6点)
1、0编程基础学习,各个节点都会卡你一下,主要是不熟悉各种报错。
2、中间有一些支线任务:比如说安装工具,会耽搁一些时间。
3、明确知道自己有拖延症的人,没必要开头就一股脑安装一堆工具,到了要用的时候再安装吧,不然很难起头开始做。mongodb、stduio-3t都是到了步骤5我才安装的
4、实在找不到问题,找会的人问一下。别人点拨一下,会更容易找到错误点。我应该是qq群里问过一个问题,其它都是百度+自己调试解决。
5、新人小白的方法:
(1)化整为零,代码一段一段跑通,这样容易推进一些。
(2)明确自己的预期结果。代码运行后,如果返回结果跟预期结果一致,那就通过;如果不一致,那就继续找问题。
6、这一天太能坐了,竟然坐了9个小时。搞完后,胸闷气短了,赶紧走走,坑爹啊,以后不能这样了!
三、总结问题,踩的坑(10个)
1、chrome中F12后,preview不显示源代码,显示的是网页或者图片。
这个是谷歌浏览器的bug,换个浏览器就好了。
2、找不到offset
筛选XHR文件,在headers栏目,Query String Parameters模块,就可以看到offset的变化。
3、xhr是什么文件类型?
xhr:XMLHttpRequest在后台与服务器交换数据,这意味着可以在不加载整个网页的情况下,对网页某部分的内容进行更新。它是Ajax的一种用法,而Ajax并不是一门语言,只是一种不需要加载整个网页,只是更新局部内容的技术。
4、json书写格式什么样?
对象:{"name":"Michael","age":24}
数组:比如:[{"name":"Michael","age":24},{"name":"Tom","age":25}]
值:{"name":"Michael", "birthday":{"month":8,"day":26}},类似于对象嵌套对象.
5、query string parameters 这是什么啊?
Query String Parameters指的就是通过在URL中携带的方式提交的参数,也就是get请求中需要的参数
6、如何简单的理解Python中的if name == 'main' 这个用法
当前理解:只运行本文件中主函数
7、多进程作用
在爬虫中主要目的是提高爬取的效率,实现秒爬
8、多进程创建和使用
在Windows上要想使用进程模块,就必须把有关进程的代码写在当前.py文件的
if __name__=='__main__':
pool = Pool() #创建进程池
语句的下面,才能正常使用Windows下的进程模块。Unix/Linux下则不需要。
9、多进程在notebook中卡死的问题。
解决办法:换在编辑器中运行,例如,我就是在sublime text运行python
10、mongodb的安装和启动
(1)下载一个mongodb安装包进行安装
(2)配置系统变量
image.png
(3)用cmd启动:
- 第一步,用cd转入mongodb的路径下:cd E:\装机软件包\mongodb\bin
-
第二步,启动:mongod --dbpath "E:\装机软件包\mongodb\data\db"
image.png
路径是指mongodb的安装路径,通过以上3步就可以启动了。
As you can see!第一个项目总是断断续续,坎坎坷坷的,不过终究还是可以解决的,继续加油吧!——2019.04.02
网友评论