2010-07-31 26 views
5

html của tôi trông giống như:BeautifulSoup, Tìm th với văn bản 'giá', sau đó nhận được giá từ ngày tiếp theo

<td> 
    <table ..> 
     <tr> 
     <th ..>price</th> 
     <th>$99.99</th> 
     </tr> 
    </table> 
</td> 

Vì vậy, tôi đang trong ô trong bảng hiện nay, làm thế nào tôi có được giá trị 99,99?

tôi có cho đến nay:

td[3].findChild('th') 

Nhưng tôi cần phải làm:

Tìm thứ với văn bản 'giá', sau đó nhận được giá trị chuỗi tiếp theo thứ tag của.

Trả lời

8

Hãy suy nghĩ về nó trong "bước". .. cho rằng một số x là gốc rễ của cây con bạn đang cân nhắc,

x.findAll(text='price') 

là danh sách của tất cả các mục trong cây con mà có chứa văn bản 'price'. Các bậc cha mẹ của những mặt hàng thì tất nhiên sẽ là:

[t.parent for t in x.findAll(text='price')] 

và nếu bạn chỉ muốn giữ lại những người có "tên" (tag) là 'th', thì tất nhiên

[t.parent for t in x.findAll(text='price') if t.parent.name=='th'] 

và bạn muốn "anh chị em tiếp theo" của những người (nhưng chỉ khi họ đang còn 'th' s), do đó

[t.parent.nextSibling for t in x.findAll(text='price') 
if t.parent.name=='th' and t.parent.nextSibling and t.parent.nextSibling.name=='th'] 

Ở đây bạn gặp sự cố với việc sử dụng một danh sách hiểu: quá nhiều sự lặp lại, vì chúng ta không thể gán kết quả trung gian cho các tên đơn giản. Vậy, nhân chuyển sang một vòng lặp cũ tốt ...:

Sửa: khoan dung gia tăng đối với một loạt các văn bản giữa cha mẹ th và "anh chị em tiếp theo" cũng như khoan dung đối với sau này trở thành một td thay vào đó, mỗi Nhận xét của OP.

for t in x.findAll(text='price'): 
    p = t.parent 
    if p.name != 'th': continue 
    ns = p.nextSibling 
    if ns and not ns.name: ns = ns.nextSibling 
    if not ns or ns.name not in ('td', 'th'): continue 
    print ns.string 

Tôi đã thêm ns.string, mà sẽ cung cấp nội dung các anh chị em tới khi và chỉ khi chúng chỉ là văn bản (không lồng nhau thẻ hơn nữa) - tất nhiên bạn có thể thay vì analize hơn nữa vào thời điểm này, phụ thuộc vào nhu cầu của ứng dụng của bạn! -). Tương tự như vậy, tôi tưởng tượng bạn sẽ không làm chỉ print nhưng một cái gì đó thông minh hơn, nhưng tôi sẽ cho bạn cấu trúc.

Nói về cấu trúc, thông báo rằng hai lần tôi sử dụng if...: continue: điều này làm giảm làm tổ so với thay thế đảo ngược tình trạng 's if và thụt tất cả các câu sau đây trong vòng lặp - và 'phẳng là tốt hơn so với lồng nhau' là một trong những koans trong Zen của Python (import this tại một dấu nhắc tương tác để xem tất cả và thiền ;-).

+0

câu trả lời tuyệt vời alex, tôi vừa mới sử dụng findAll cho đến nay và bây giờ tôi cảm thấy tôi có thể đi ngang qua dom với kiến ​​thức này, đi python! hehe – Blankman

+0

trong liên kết 'if not ns or ns.name ...', nếu ns là None thì ns.name sẽ thất bại không? – Blankman

+0

thực sự HTML của tôi giống như: giá $ 99.99 và p.nextSibling trống, tôi đã thử p.next và điều đó không hoạt động. – Blankman

0

Với pyparsing, thật dễ dàng để đạt được vào giữa một số HTML cho một mẫu thẻ như thế này:

from pyparsing import makeHTMLTags, Combine, Word, nums 

th,thEnd = makeHTMLTags("TH") 
floatnum = Combine(Word(nums) + "." + Word(nums)) 
priceEntry = (th + "price" + thEnd + 
       th + "$" + floatnum("price") + thEnd) 

tokens,startloc,endloc = priceEntry.scanString(html).next() 

print tokens.price 

makeHTMLTags helper Pyparsing trả về một cặp biểu pyparsing, một cho thẻ bắt đầu và một cho thẻ kết thúc. Mẫu thẻ bắt đầu là nhiều hơn chỉ cần thêm "<>" xung quanh chuỗi đã cho, nhưng cũng cho phép thêm khoảng trắng, trường hợp biến và sự hiện diện hoặc vắng mặt của thuộc tính thẻ. Ví dụ, lưu ý rằng mặc dù tôi đã chỉ định "TH" làm thẻ đầu bảng, nó cũng sẽ khớp với "th", "Th", "tH" và "TH". Hành vi bỏ qua khoảng trống mặc định của Pyparsing cũng sẽ xử lý các khoảng trống thừa, giữa thẻ và "$", giữa "$" và giá số, v.v., mà không phải rải "không hoặc nhiều khoảng trắng ký tự có thể đi ở đây" chỉ báo. Cuối cùng, bằng cách chỉ định tên kết quả "giá" (theo sau floatum trong định nghĩa priceEntry), nó làm cho nó rất đơn giản để truy cập vào giá trị cụ thể từ danh sách đầy đủ các thẻ khớp với biểu thức tổng thể priceEntry.

(Kết hợp được sử dụng cho 2 mục đích: nó không cho phép khoảng trắng giữa các thành phần của số; và trả về một mã thông báo kết hợp duy nhất "99,99" thay vì danh sách ["99", ".", "99"].)

Các vấn đề liên quan