周天我也没课的,您给安排一下吧!:)——致某某某
最近系统的开始了爬虫的学习,虽然以前也写过不少,但是现在跟着书学,感觉学会了不少,这里来分享一下。
我们今天的目标是猫眼电影top100
将要用到的库:
import re
import requests
import time
import json
from requests.exceptions import RequestException
网址——https://maoyan.com/board/4,用浏览器打开:
![](https://img.haomeiwen.com/i15391438/41bc8f1bbb4d6efb.png)
这是猫眼首页,我们需要的信息在这里都可以看到——电影排名、电影图片、电影名、主演、上映时间、评分。
这次我没用BeautifulSoup库来解析html,用的是正则表达式,刚好学过,就赶紧试用了下。打开网页后按F12,打开开发者工具,在调试一栏中打开源码。不要在查看器、element里查看,因为这里面的可能是JavaScript渲染过后的文件,并不是我们得到的响应源码。
![](https://img.haomeiwen.com/i15391438/eee869ffc956e240.png)
经过观察,我们要的信息在<dd>...</dd>标签里,经过一下午的反复练习,我想出来一个正则表达式的快速写法:先把保存着我们要的信息的<dd>...</dd>标签直接拿出来:
<dd>
<i class="board-index board-index-1">1</i>
<a href="/films/1203" title="霸王别姬" class="image-link" data-act="boarditem-click" data-val="{movieId:1203}">
<img src="//s0.meituan.net/bs/?f=myfe/mywww:/image/loading_2.e3d934bf.png" alt="" class="poster-default" />
<img data-src="https://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c" alt="霸王别姬" class="board-img" />
</a>
<div class="board-item-main">
<div class="board-item-content">
<div class="movie-item-info">
<p class="name"><a href="/films/1203" title="霸王别姬" data-act="boarditem-click" data-val="{movieId:1203}">霸王别姬</a></p>
<p class="star">
主演:张国荣,张丰毅,巩俐
</p>
<p class="releasetime">上映时间:1993-01-01</p> </div>
<div class="movie-item-number score-num">
<p class="score"><i class="integer">9.</i><i class="fraction">5</i></p>
</div>
</div>
</div>
</dd>
然后将我们要的信息改成: (.?),找到标志位,将其余字符全部用:.? 替代。
如下:
<dd>.*?board-index.*?>(.*?)</i>.*?data-src="('+
'.*?)".*?"name"><a.*?>(.*?)</a>.*?star">('+
'.*?)</p>.*?releasetime">(.*?)</p>.*?integer">('+
'.*?)</i>.*?fraction">(.*?)</i>.*?</dd>
所以就有了我们的解析页面的函数:
def parser_one_page(html):
'''
解析一页的10部电影信息
输入html对象
输出需要的信息->dict
<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?
name.*?a.*?>(.*?)</a>.*?"star">(.*?)</p>.*?releasetime"
>(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>
'''
pattern = re.compile('<dd>.*?board-index.*?>(.*?)</i>.*?data-src="('+
'.*?)".*?"name"><a.*?>(.*?)</a>.*?star">('+
'.*?)</p>.*?releasetime">(.*?)</p>.*?integer">('+
'.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)
items = re.findall(pattern, html)
for i in items:
yield {
'index': i[0],
'image': i[1],
'name': i[2],
'actor': i[3].strip()[3:],
'releasetime': i[4].strip()[5:],
'score': i[5]+i[6],
}
前面要获取首页源码:
def get_one_page(url):
'''
获取猫眼top100的一页源码
输入网页url
输出源码'''
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0)'
' Gecko/20100101 Firefox/66.0'}
response = requests.get(url, headers=headers)
if response.status_code == 200:
print(200)
return response.text
return None
except RequestException:
return None
然后是将其保存到文件:
def write_to_file(content):
'''将处理完成的文件放到
输入处理好的内容
将内容存储到文件'''
with open('result.txt', 'a', encoding='utf-8') as f:
f.write(json.dumps(content, ensure_ascii=False) + '\n')
main函数:
def main(offset):
'''输入每一页的偏移量'''
url = "https://maoyan.com/board/4?offset="+str(offset)
html = get_one_page(url)
contents = parser_one_page(html)
for item in contents:
print(item)
write_to_file(item)
我发现换页后url多了一个偏移量offset,每页10部电影,即第一页从0开始,第二页从10开始,一次类推,得出:0,10,20,......,90,一共10页,我们写个循环:
if __name__ == "__main__":
for i in range(10):
main(i*10)
time.sleep(1)
因为猫眼有反爬机制,访问速度过快,会被禁止访问,所以我们用了1s的延时。
运行后的成果:
![](https://img.haomeiwen.com/i15391438/a9b5593f76141df1.png)
![](https://img.haomeiwen.com/i15391438/912d6273142ba9d7.png)
这次我们用的是requests库,这比urllib好用很多,用了正则表达式代替beautifulsoup,用了json数据格式来存储数据,非常简单,正则表达式很强大!几乎万能,就是当式子较长后比较闹心。
就这样!
全部代码:
import re
import requests
import time
import json
from requests.exceptions import RequestException
def get_one_page(url):
'''
获取猫眼top100的一页源码
输入网页url
输出源码'''
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0)'
' Gecko/20100101 Firefox/66.0'}
response = requests.get(url, headers=headers)
if response.status_code == 200:
print(200)
return response.text
return None
except RequestException:
return None
def parser_one_page(html):
'''
解析一页的10部电影信息
输入html对象
输出需要的信息->dict
<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?"star">(.*?)</p>.*?releasetime">(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>
'''
# regex='<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(' \
# '.*?)</a>.*?"star">(.*?)</p>.*?"releasetime">(.*?)</p>.*?"integer">(' \
# '.*?)</li>.*?"fraction">(.*?)</i>'
pattern = re.compile('<dd>.*?board-index.*?>(.*?)</i>.*?data-src="('+
'.*?)".*?"name"><a.*?>(.*?)</a>.*?star">('+
'.*?)</p>.*?releasetime">(.*?)</p>.*?integer">('+
'.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)
items = re.findall(pattern, html)
for i in items:
yield {
'index': i[0],
'image': i[1],
'name': i[2],
'actor': i[3].strip()[3:],
'releasetime': i[4].strip()[5:],
'score': i[5]+i[6],
}
def write_to_file(content):
'''将处理完成的文件放到
输入处理好的内容
将内容存储到文件'''
with open('result.txt', 'a', encoding='utf-8') as f:
f.write(json.dumps(content, ensure_ascii=False) + '\n')
def main(offset):
'''输入每一页的偏移量'''
url = "https://maoyan.com/board/4?offset="+str(offset)
html = get_one_page(url)
contents = parser_one_page(html)
for item in contents:
print(item)
write_to_file(item)
if __name__ == "__main__":
for i in range(10):
main(i*10)
time.sleep(1)
闲话我不放pyq了。只放简书,免得受您一顿批。
网友评论