1. 打開google瀏覽器,輸入www.toutiao.com, 搜索街拍。html
2.打開開發者選項,network監看加載的xhr, 數據是ajax異步加載的,能夠看到preview裏面的data數據python
3.下拉刷新查看加載的offset,每次加載20條數據,data是json數據,裏面的article_url,是圖集詳情頁的url。git
4.首先抓取索引頁的內容github
data數據來自於索引頁的請求都裏面的query strajax
1 # 提取索引頁的數據 2 def get_page_index(offset, keyword): 3 data = { 4 'offset': offset, 5 'format': 'json', 6 'keyword': keyword, 7 'autoload': 'true', 8 'count': 20, 9 'cur_tab': 1 10 } 11 # 向路由中出入參數, 構建完整url 12 url = 'http://www.toutiao.com/search_content/?' + urlencode(data) 13 try: 14 response = requests.get(url) 15 if response.status_code == 200: 16 return response.text 17 return None 18 except RequestException: 19 print('請求索引頁出錯') 20 return None
5. 接下來是解析索引頁的數據,提取出所須要的詳情頁的url,索引頁的data是json數據,裏面的article_url,是圖集詳情頁的url。mongodb
1 # 解析索引頁的json數據(Preview),並提取詳情頁url 2 def parse_page_index(html): 3 try: 4 data = json.loads(html) 5 if data and 'data' in data.keys(): 6 for item in data.get('data'): 7 # 用生成器的方式,惰性獲取詳情頁的url 8 yield item.get('article_url') 9 except JSONDecodeError: 10 pass
6. 有了詳情頁的url,接下來就是獲取詳情頁的數據和代碼了數據庫
1 # 獲取詳情頁面的數據代碼 2 def get_page_detail(url): 3 try: 4 response = requests.get(url, timeout=5) 5 if response.status_code == 200: 6 return response.text 7 return None 8 except RequestException: 9 print('請求詳情頁出錯', url) 10 return None
7. 接着就是解析詳情頁面,並提取title, 和圖片url, 詳情頁代碼數據在Doc中查看, 注意提取的是組圖,非組圖被過濾了.url_list 是指三個地址都是圖片的地址,咱們只要有一個原始的url就能夠了。
以某個詳情頁爲例,在瀏覽器中輸入http://www.toutiao.com/a6473742013958193678/。開發者選項,network, Docjson
1 # 解析詳情頁面並提取title, 和圖片url 2 def parse_page_detail(html, url): 3 soup = BeautifulSoup(html, 'lxml') 4 title = soup.select('title')[0].get_text() 5 print(title) 6 images_pattern = re.compile(r'gallery: (.*?),\n') 7 result = re.search(images_pattern, html) 8 if result: 9 # 將json數據轉換爲python的字典對象 10 data = json.loads(result.group(1)) 11 if data and 'sub_images' in data.keys(): 12 sub_images = data.get('sub_images') 13 images = [item.get('url') for item in sub_images] 14 for image in images: download_image(image)
# 返回標題,此詳情頁的url,和圖片url列表 15 return { 16 'title': title, 17 'url': url, 18 'images': images 19 }
8. 把解析提取的數據存儲到mongodb中,以字典的方式.瀏覽器
先寫個mongo的配置文件config.py多線程
1 MONGO_URL = 'localhost' 2 MONGO_DB = 'toutiao' 3 MONGO_TABLE = 'toutiao' 4 5 GROUP_START = 0 6 GROUP_END = 20 7 8 KEYWORD = '街拍'
而後鏈接本地mongo,存儲數據
1 client = pymongo.MongoClient(MONGO_URL, connect=False) # connect=False防止多線程在後臺屢次鏈接mongo數據庫 2 db = client[MONGO_DB] 3 4 # 把詳情頁面的url和標題(title)以及組圖的地址list保存到mongo中 5 def save_to_mongo(result): 6 if db[MONGO_TABLE].insert(result): 7 print('存儲到MongoDB成功', result) 8 return True 9 return False
9. 下載圖片
1 # 下載圖數據,並保存圖片 2 def download_image(url): 3 print('正在下載', url) 4 try: 5 response = requests.get(url) 6 if response.status_code == 200: 7 # response.content 爲二進制數據 8 save_image(response.content) 9 return None 10 except RequestException: 11 print('請求圖片失敗', url) 12 return None 13 14 15 # 保存圖片 16 def save_image(content): 17 # 使用md5生成加密名字,同時防止相同的圖片重複下載 18 file_path = '{0}/{1}.{2}'.format(os.getcwd(), md5(content).hexdigest(), 'jpg') 19 if not os.path.exists(file_path): 20 with open(file_path, 'wb') as f: 21 f.write(content)
10. 爬蟲主函數
1 def main(offset): 2 html = get_page_index(offset, KEYWORD) 3 for url in parse_page_index(html): 4 html = get_page_detail(url) 5 if html: 6 result = parse_page_detail(html, url) 7 if result: save_to_mongo(result)
11. 開啓多進程
1 if __name__ == '__main__': 2 groups = [x * 20 for x in range(GROUP_START, GROUP_END)] 3 pool = Pool() 4 pool.map(main, groups)
12. 須要的庫函數
1 import requests 2 import re 3 import pymongo 4 from urllib.parse import urlencode 5 from requests.exceptions import RequestException 6 from json.decoder import JSONDecodeError 7 from bs4 import BeautifulSoup 8 import json 9 import os 10 from hashlib import md5 11 from config import * 12 from multiprocessing import Pool
完整代碼: https://github.com/huazhicai/Spider/tree/master/jiepai