1. 打开google浏览器,输入www.toutiao.com, 搜索街拍。
2.打开开发者选项,network监看加载的xhr, 数据是ajax异步加载的,可以看到preview里面的data数据
3.下拉刷新查看加载的offset,每次加载20条数据,data是json数据,里面的article_url,是图集详情页的url。
4.首先抓取索引页的内容
data数据来自于索引页的请求都里面的query str
1 #提取索引页的数据
2 defget_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 returnresponse.text17 returnNone18 exceptRequestException:19 print('请求索引页出错')20 return None
5. 接下来是解析索引页的数据,提取出所需要的详情页的url,索引页的data是json数据,里面的article_url,是图集详情页的url。
1 #解析索引页的json数据(Preview),并提取详情页url
2 defparse_page_index(html):3 try:4 data =json.loads(html)5 if data and 'data' indata.keys():6 for item in data.get('data'):7 #用生成器的方式,惰性获取详情页的url
8 yield item.get('article_url')9 exceptJSONDecodeError:10 pass
6. 有了详情页的url,接下来就是获取详情页的数据和代码了
1 #获取详情页面的数据代码
2 defget_page_detail(url):3 try:4 response = requests.get(url, timeout=5)5 if response.status_code == 200:6 returnresponse.text7 returnNone8 exceptRequestException:9 print('请求详情页出错', url)10 return None
7. 接着就是解析详情页面,并提取title, 和图片url, 详情页代码数据在Doc中查看, 注意提取的是组图,非组图被过滤了.url_list 是指三个地址都是图片的地址,我们只要有一个原始的url就可以了。
以某个详情页为例,在浏览器中输入http://www.toutiao.com/a6473742013958193678/。开发者选项,network, Doc
1 #解析详情页面并提取title, 和图片url
2 defparse_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 ifresult:9 #将json数据转换为python的字典对象
10 data = json.loads(result.group(1))11 if data and 'sub_images' indata.keys():12 sub_images = data.get('sub_images')13 images = [item.get('url') for item insub_images]14 for image inimages: download_image(image)
# 返回标题,此详情页的url,和图片url列表15 return{16 'title': title,17 'url': url,18 'images': images19 }
8. 把解析提取的数据存储到mongodb中,以字典的方式.
先写个mongo的配置文件config.py
1 MONGO_URL = 'localhost'
2 MONGO_DB = 'toutiao'
3 MONGO_TABLE = 'toutiao'
4
5 GROUP_START =06 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 defsave_to_mongo(result):6 ifdb[MONGO_TABLE].insert(result):7 print('存储到MongoDB成功', result)8 returnTrue9 return False
9. 下载图片
1 #下载图数据,并保存图片
2 defdownload_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 returnNone10 exceptRequestException:11 print('请求图片失败', url)12 returnNone13
14
15 #保存图片
16 defsave_image(content):17 #使用md5生成加密名字,同时防止相同的图片重复下载
18 file_path = '{0}/{1}.{2}'.format(os.getcwd(), md5(content).hexdigest(), 'jpg')19 if notos.path.exists(file_path):20 with open(file_path, 'wb') as f:21 f.write(content)
10. 爬虫主函数
1 defmain(offset):2 html =get_page_index(offset, KEYWORD)3 for url inparse_page_index(html):4 html =get_page_detail(url)5 ifhtml: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 inrange(GROUP_START, GROUP_END)]3 pool =Pool()4 pool.map(main, groups)
12. 需要的库函数
1 importrequests2 importre3 importpymongo4 from urllib.parse importurlencode5 from requests.exceptions importRequestException6 from json.decoder importJSONDecodeError7 from bs4 importBeautifulSoup8 importjson9 importos10 from hashlib importmd511 from config import *
12 from multiprocessing import Pool
完整代码: https://github.com/huazhicai/Spider/tree/master/jiepai