• 爬取今日头条街拍美图


      1 import requests
      2 from bs4 import BeautifulSoup
      3 import json,re,os
      4 from urllib.parse import urlencode
      5 from hashlib import md5
      6 from multiprocessing.pool import Pool
      7 from requests.exceptions import RequestException
      8 import pymongo
      9 #引入模块config中所有变量
     10 from config import *
     11 from json.decoder import JSONDecodeError
     12 
     13 #声明MongoDB对象
     14 client = pymongo.MongoClient(MONGO_URL,connect=False)
     15 db = client[MONGO_DB]
     16 #这里插入到MongoDB。
     17 #保存到本地
     18 def save_to_mongo(result):
     19     if db[MONGO_TABLE].insert(result):
     20         print('存储到MongoDB成功',result)
     21         return True
     22     else:
     23         return False
     24 #获取索引页数据
     25 def get_page_index(offset,keyword):
     26     data = {
     27         'offset': offset,
     28         'format': 'json',
     29         'keyword': keyword,
     30         'autoload': 'true',
     31         'count': '20',
     32         'cur_tab': '3',
     33         'from':'gallery'
     34     }
     35     #将data变成请求参数
     36     url = 'https://www.toutiao.com/search_content/?'+urlencode(data)
     37     try:
     38         response = requests.get(url)
     39         response.raise_for_status()
     40         response.encoding = response.apparent_encoding
     41         return response.text
     42     except RequestException:
     43         print('爬取索引页失败!')
     44 #解析索引页
     45 def parse_page_index(html):
     46     # 获取所有详情页的url
     47     try:
     48         # 页面是json格式的,装换成字符串格式
     49         data = json.loads(html)
     50         # data.keys()返回所有键名
     51         if data and 'data' in data.keys():
     52             for item in data.get('data'):
     53                 if item.get('cell_type') is not None:
     54                     continue
     55                 yield item.get('article_url')
     56     except JSONDecodeError:
     57         pass
     58 
     59 def get_page_detail(url):
     60     # 请求详情页的url
     61 
     62     #这里不加 headers 是获取不到数据的。
     63     headers = {'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 '}
     64     try:
     65         response = requests.get(url,headers=headers)
     66         response.raise_for_status()
     67         response.encoding = response.apparent_encoding
     68         return response.text
     69     except RequestException:
     70         print('爬取详情页失败!',url)
     71         return None
     72 
     73 def parse_page_detail(html,url):
     74     '''获取详情页的标题和图片地址url'''
     75 
     76     #利用BeautifulSoup库提取标题
     77     try:
     78         soup = BeautifulSoup(html,'lxml')
     79         title = soup.select('title')[0].get_text()
     80         if title: print(title)
     81     except:
     82         pass
     83 
     84     # 利用正则表达式提取图片地址
     85     images_pattern = re.compile(r'.*?gallery: JSON.parse("(.*?)")',re.S|re.M)
     86     result = re.search(images_pattern,html)
     87 
     88     if result:
     89         data = json.loads(result.group(1).replace('\',''))
     90         #print(data)
     91         if data and 'sub_images' in data.keys():
     92             sub_images = data.get('sub_images')
     93             #提取图片
     94             images = [item.get('url') for item in sub_images]
     95             #保存图片到本地
     96             for image in images:
     97                 download_image(title,image)
     98             return {'title':title,
     99                     'url':url,
    100                     'images':images}
    101     else:
    102         print('')
    103 
    104 def save_image(title,result):
    105     img_path = 'image' + os.path.sep + title
    106     if not os.path.exists(img_path):
    107         os.makedirs(img_path)
    108     file_path = '{0}/{1}.{2}'.format(img_path,md5(result).hexdigest(),'jpg')
    109     if not os.path.exists(file_path):
    110         with open(file_path,'wb') as f:
    111             f.write(result)
    112         print("%s下载完成"%file_path)
    113     else:
    114         print("%s已经存在"%file_path)
    115 
    116 def download_image(title,url):
    117     try:
    118         print('正在下载',url)
    119         r = requests.get(url)
    120         r.raise_for_status()
    121         r.encoding=r.apparent_encoding
    122         save_image(title,r.content)
    123 
    124     except RequestException:
    125         print('请求图片出错',url)
    126         return False
    127 
    128 def main(offset):
    129     #调用函数
    130     html= get_page_index(offset,KEYWORD)
    131     for url in parse_page_index(html):
    132         html = get_page_detail(url)
    133         if html:
    134             result = parse_page_detail(html,url)
    135             # print(result)
    136             if result: save_to_mongo(result)
    137 
    138 
    139 
    140 if __name__=='__main__':
    141     #开启多线程抓取
    142     pool = Pool()
    143     group = [x*20 for x in range(GROUP_START,GROUP_END+1)]
    144     pool.map(main,group)
    145     pool.close()

    以上是spider.py

    借鉴:https://blog.csdn.net/sixkery/article/details/81836017

    有两个坑我遇到的:

    第一个坑
    如果你点击图集,打开开发者工具,刷新一下,你会发现,你的页面在综合这一栏。
    你会发现你找到的上图的参数跟我的不一样。
    这里你可以刷新之后点击图集,然后向下拖动几个,让页面多加载一些。
    其中「cur_tab:3」这个参数中的数字对应图集,这下你明白了吧。
    到这里就好办了,我们点击 Preview


    可以看到 data 下方有 article_url 当然还有 image_url ,你点击 image_url 你会发现只有四个 url ,复制链接在浏览器上打开你发现 TMD 还不是大图,还是缩略图,所以我们不用它,我们获取 article_url ,获取之后再次请求不就完了吗。


    分析详情页
    这里我们来看看详情页的内容

     


    详情页分析
    这里我们随便点开一个组图的 url 来分析,我们可以看到返回的数据是一大堆 html ,这里有必要说一下,我们在获取页面内容的时候,一般浏览器会返回给我们的是 response 里的内容。但是我们大多数爬取数据,用 xpath 、BeautifulSoup 获取数据,看的是 Elements 里的内容。这里一定要看看 response 里的内容和 Element 里的是否相同。
    这里的图片地址还真是不好找,具体怎么找呢,点开图片的地址,复制下链接,在HTML里「Ctrl + F」就发现了。是在红色框里面的。

    第二个坑

    首先,这里获取的页面内容是 json 格式的,我们看一下这里的内容



    详情页json
    这里获取用BeautifulSoup 获取 title 很方便,直接去第一个 title 就好了,关键就在这个image的提取。


    image.png
    这里是在红色框里的,这里涉及到了正则的用法,代码里用到了反斜杠,这里是转义匹配,要不然正则会匹配不到想要的数据。
    还有在源代码中出现了好多反斜杠,不去除掉还是没办法匹配。
    这些坑跨过之后就一帆风顺了。

    配置文件

     1 '''配置文件'''
     2 
     3 
     4 #链接地址
     5 MONGO_URL='localhost'
     6 
     7 #数据库名称
     8 MONGO_DB='toutiao'
     9 
    10 #表名称
    11 MONGO_TABLE='toutiao'
    12 
    13 GROUP_START=1
    14 GROUP_END=20
    15 
    16 KEYWORD = '街拍'

    另一种爬取今日头条美图

     1 import requests
     2 from urllib.parse import urlencode
     3 from requests import codes
     4 import os
     5 from hashlib import md5
     6 from multiprocessing.pool import Pool
     7 
     8 
     9 def get_page(offset):
    10     params = {
    11         'offset': offset,
    12         'format': 'json',
    13         'keyword': '街拍',
    14         'autoload': 'true',
    15         'count': '20',
    16         'cur_tab': '1',
    17         'from': 'search_tab'
    18     }
    19     base_url = 'https://www.toutiao.com/search_content/?'
    20     url = base_url + urlencode(params)
    21     try:
    22         resp = requests.get(url)
    23         if codes.ok == resp.status_code:
    24             return resp.json()
    25     except requests.ConnectionError:
    26         return None
    27 
    28 
    29 def get_images(json):
    30     if json.get('data'):
    31         data = json.get('data')
    32         for item in data:
    33             if item.get('cell_type') is not None:
    34                 continue
    35             title = item.get('title')
    36             images = item.get('image_list')
    37             for image in images:
    38                 yield {
    39                     'image': 'https:' + image.get('url'),
    40                     'title': title
    41                 }
    42 
    43 
    44 def save_image(item):
    45     img_path = 'img' + os.path.sep + item.get('title')
    46     if not os.path.exists(img_path):
    47         os.makedirs(img_path)
    48     try:
    49         resp = requests.get(item.get('image'))
    50         if codes.ok == resp.status_code:
    51             file_path = img_path + os.path.sep + '{file_name}.{file_suffix}'.format(
    52                 file_name=md5(resp.content).hexdigest(),
    53                 file_suffix='jpg')
    54             if not os.path.exists(file_path):
    55                 with open(file_path, 'wb') as f:
    56                     f.write(resp.content)
    57                 print('Downloaded image path is %s' % file_path)
    58             else:
    59                 print('Already Downloaded', file_path)
    60     except requests.ConnectionError:
    61         print('Failed to Save Image,item %s' % item)
    62 
    63 
    64 def main(offset):
    65     json = get_page(offset)
    66     for item in get_images(json):
    67         print(item)
    68         save_image(item)
    69 
    70 
    71 GROUP_START = 0
    72 GROUP_END = 7
    73 
    74 if __name__ == '__main__':
    75     pool = Pool()
    76     groups = ([x * 20 for x in range(GROUP_START, GROUP_END + 1)])
    77     pool.map(main, groups)
    78     pool.close()
    79     pool.join()
  • 相关阅读:
    网络安全协议(1)
    CG-CTF(6)
    CG-CTF(5)
    CG-CTF(4)
    CG-CTF(3)
    MAC地址欺骗(原理及实验)
    CG-CTF(2)
    CG-CTF(1)
    【转载】Spring Boot【快速入门】2019.05.19
    【编程大系】Java资源汇总
  • 原文地址:https://www.cnblogs.com/qqw-1995/p/9921713.html
Copyright © 2020-2023  润新知